tag:blogger.com,1999:blog-82504296565327831882024-03-18T09:47:48.824+00:00Trevor AppletonRaspberry Pi / Python / Project ManagementTrevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.comBlogger37125tag:blogger.com,1999:blog-8250429656532783188.post-55410270377067225722017-10-19T20:12:00.000+01:002017-10-23T20:21:21.428+01:00The Power of Habit - Book ReviewThe Power of Habit, written by Charles Duhigg, a New York Times reporter is both a fascinating and informative book. Duhigg takes a trip into the human mind and helps explain why we do what we do. Throughout the book Duhingg backs up his ideas with interesting anecdotes both about experiments conducted to research individuals habits, and experiences people have been through. All of this is written in an easy to read manner, which ensures the pages keep turning.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://t2.gstatic.com/images?q=tbn:ANd9GcTypMAkikrkhpVatoOrOhDGIRjHYE50y4yd7E_WxGtmp6TOdjCZ" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="800" data-original-width="521" height="320" src="https://t2.gstatic.com/images?q=tbn:ANd9GcTypMAkikrkhpVatoOrOhDGIRjHYE50y4yd7E_WxGtmp6TOdjCZ" width="208" /></a></div>
<br />
<br />
While the whole book touches on habits, it examines them into three distinct sections.<br />
<br />
Part 1 - The habit of individuals<br />
Part 2 - The habits of successful organisations<br />
Part 3 - The habits of societies.<br />
<br />
There is a very small section on the end which is a readers guide to using these ideas.<br />
<br />
While these three sections are very much linked through looking at habits, each one could stand alone in its own right. Looking at these three distinct areas really makes you appreciate the power of being able to tap into habits. <br />
<br />
Part 1 of the book deals with why people have habits, and how the brain ensures you a carry out certain activities almost subconsciously. The three aspects of habits are discussed.<br />
<br />
<div style="text-align: center;">
Cue —> Routine —> Reward</div>
<br />
It certainly makes you more self aware about why you do certain things, and what you can do to change.<br />
<br />
Part 2 then jumps into examining organisations, which was absolutely fascinating. From how an American Football coach went on to win the Super Bowl by changing players habits, to how Starbucks became a world leader. How a crisis can bring a company together, to how supermarkets know what you want to buy before you do! Quite wide ranging topics, but all linked with how scientific, and once you realise, how obvious habits are.<br />
<br />
Finally in Part 3, Duhigg looks into how societies can change through habit. Duhigg uses the powerful anecdote of Rosa Parks, and how a small incident transformed a nation. In this section we also look at societies views on peoples habits, which touches on the moral and legal aspects of Habits.<br />
<br />
When dealing with each of thee topics, whether explaining the science, or the history of what happened, Duhigg gets the level of detail right. You certainly don’t feel bogged down in the science, or too involved in the minute details of the history.<br />
<br />
If I had to level any criticism at the book it would be that I felt the first part of the book was a little repetitive. While the final section on how readers should implement these ideas came across as a little bit of an after thought, and may have been better implemented in Part 1. However this should not put you off reading the book, but if you do find the book a little slow at first, it is absolutely worth persevering, as it matures as you progress.<br />
<br />
Don’t be fooled into thinking this book is only for those who would like to stop biting their nails. When laid out in front of you, from so many perspectives you become aware that your habits control your life more than you realise. Even if you don’t have any habits that you want to manipulate, after reading this book, you will become aware your habits are already being manipulated by others, without your consent.Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com8tag:blogger.com,1999:blog-8250429656532783188.post-1192739558601979542017-09-28T21:25:00.001+01:002017-09-28T21:25:41.773+01:00The Checklist Manifesto - Book ReviewWhen I was handed the checklist manifesto and told it is a fascinating book about the power of checklists, I was somewhat sceptical. A book about checklists? Everyone knows about checklists, don't they? A few boxes to tick when things are done. But how on earth does anyone write a whole book about them? I was curious.<br />
<br />
Within minutes of starting the book, I was hooked.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://t1.gstatic.com/images?q=tbn:ANd9GcQtUAgIXaYUSofbEHU73EjFL-jV7-tqGdUqtwIuUSu5nPDIXrpH" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="800" data-original-width="521" height="320" src="https://t1.gstatic.com/images?q=tbn:ANd9GcQtUAgIXaYUSofbEHU73EjFL-jV7-tqGdUqtwIuUSu5nPDIXrpH" width="208" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<br />
The author Atul Gawande is a general and endocrine surgeon, who also runs the World Health Organisations Safe Surgery Saves Lives Program. The book takes you through Gawandes quest to find a method of improving healthcare and saving lives. While it focusses heavily on the authors experience in the medical world, it absolutely is not a book written for the medical profession.<br />
<br />
Gawande takes a peek into other industries, and how they have solved hugely complex problems. Flying planes which experienced test pilots have crashed, building skyscrapers, finance, even operating a top restaurant. The secret to success? The humble checklist. Gawande states we have more knowledge than we ever have had, but the volume and complexity of what we know has exceeded our individual ability to deliver its benefits correctly. The secret to success? The humble checklist.<br />
<br />
Through his research of other industries and his own implementation of a checklist for the World Health Organisation Gawande shows some statistics demonstrating the power of checklists. These are simply staggering, to the point that when Gawande first saw the results of a checklist he had implemented, he could not believe them.<br />
<br />
So why are checklists not implemented in more places? The book covers the fallacies of humans, and how they think a humble checklist is beneath them. For anyone who has tried to implement a new system in the work place, they will recognise the resistance seen by Gawande while trying to get others to adopt his method. Many people believe that a simple checklist is beneath them. However stories such as the pilots and crew of the plane which landed in the Hudson River in Manhattan soon remind you of their power. Was this ‘miracle’ down to the pilots skill; or the pilots checklist?<br />
<br />
So while this book is about the humble checklist, and the vast benefits they can reap, it’s about so much more. Ticking boxes is not the ultimate goal. It’s about encouraging a culture of teamwork. It’s about recognising even the smartest, highly trained people can make mistakes. It’s about looking outside your world and learning from other industries. It’s about empowering staff. It’s about becoming more efficient.<br />
<br />
Gawande has written an easy to read engaging book with a powerful message. I found it so compelling that when I reached the end, I turned straight back to page one and read it again. It is that good. I would encourage you all, even if you feel a checklist is beneath you, to follow the checklist I have created below.<br />
<br />
<br />
Read this book.<br />
Read it again.<br />
<div>
<br /></div>
Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com9tag:blogger.com,1999:blog-8250429656532783188.post-34346710637407162052016-02-01T12:25:00.000+00:002017-09-28T21:33:31.788+01:00Turn Your Raspberry Pi into a TwitterbotOk. So this was a post I had decided I was not going to write. The reason for this is I did not want to help people create something negative, such as a spam generator.<br />
<br />
Then I had a quick look at the <a href="https://en.wikipedia.org/wiki/Twitterbot" target="_blank">Wikipedia page about Twitterbots</a>. I realised there are some really fantastic ideas out there for Twitterbots, which can have a positive impact.<br />
<br />
So I decided to go ahead and write the blog post, and to trust people to use it the right way. :-)<br />
<br />
Besides, one of the the Twitterbots I have written is testing the <a href="https://en.wikipedia.org/wiki/Infinite_monkey_theorem" target="_blank">Infinite Monkey Theorem</a> to <a href="http://trevorappleton.blogspot.co.uk/2014/10/infinite-monkey-theorem-using-python.html" target="_blank">simulate a monkey trying to type the complete works of Shakespeare</a>. The monkey automatically tweets his progress (<a href="https://twitter.com/themonkeybard" target="_blank">@TheMonkeyBard</a>).<br />
<br />
So who am I to judge? :-)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://upload.wikimedia.org/wikipedia/commons/f/f1/Monkey-typing.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="356" data-original-width="633" height="179" src="https://upload.wikimedia.org/wikipedia/commons/f/f1/Monkey-typing.jpg" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<br />
In this blog post I am going to show you how I wrote another Twitterbot, which sends out a tweet, from a list of pre-written tweets, at a certain time. For me I use it to automatically post my blogs to twitter at certain times of the day. To disguise the fact I am doing this, I have added a slight element of randomness in there, so it doesn't look too much like a Twitterbot. More on that later.<br />
<br />
To start with here is the code in its entirety. Have a read through it and see if it makes sense to you, we will then run through this line by line.<br />
<br />
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: green; font-weight: bold;">from</span> <span class="nn" style="color: blue; font-weight: bold;">__future__</span> <span class="kn" style="color: green; font-weight: bold;">import</span> <span class="n">print_function</span> <span class="c1" style="color: #408080; font-style: italic;">#Allows python3 use of print()</span>
<span class="kn" style="color: green; font-weight: bold;">import</span> <span class="nn" style="color: blue; font-weight: bold;">random</span>
<span class="kn" style="color: green; font-weight: bold;">import</span> <span class="nn" style="color: blue; font-weight: bold;">string</span>
<span class="kn" style="color: green; font-weight: bold;">import</span> <span class="nn" style="color: blue; font-weight: bold;">tweepy</span>
<span class="kn" style="color: green; font-weight: bold;">import</span> <span class="nn" style="color: blue; font-weight: bold;">os</span>
<span class="n">FILEPATH</span> <span class="o" style="color: #666666;">=</span> <span class="s1" style="color: #ba2121;">'/home/pi/Desktop/TwitterBot'</span>
<span class="c1" style="color: #408080; font-style: italic;"># Consumer keys and access tokens, used for OAuth </span>
<span class="n">consumer_key</span> <span class="o" style="color: #666666;">=</span> <span class="s1" style="color: #ba2121;">'YourConsumerKey'</span>
<span class="n">consumer_secret</span> <span class="o" style="color: #666666;">=</span> <span class="s1" style="color: #ba2121;">'YourConsumerSecret'</span>
<span class="n">access_token</span> <span class="o" style="color: #666666;">=</span> <span class="s1" style="color: #ba2121;">'YourAccessToken'</span>
<span class="n">access_token_secret</span> <span class="o" style="color: #666666;">=</span> <span class="s1" style="color: #ba2121;">'YourAccessTokenSecret'</span>
<span class="c1" style="color: #408080; font-style: italic;"># OAuth process, using the keys and tokens</span>
<span class="n">auth</span> <span class="o" style="color: #666666;">=</span> <span class="n">tweepy</span><span class="o" style="color: #666666;">.</span><span class="n">OAuthHandler</span><span class="p">(</span><span class="n">consumer_key</span><span class="p">,</span> <span class="n">consumer_secret</span><span class="p">)</span>
<span class="n">auth</span><span class="o" style="color: #666666;">.</span><span class="n">set_access_token</span><span class="p">(</span><span class="n">access_token</span><span class="p">,</span> <span class="n">access_token_secret</span><span class="p">)</span>
<span class="c1" style="color: #408080; font-style: italic;"># Creation of the actual interface, using authentication</span>
<span class="n">api</span> <span class="o" style="color: #666666;">=</span> <span class="n">tweepy</span><span class="o" style="color: #666666;">.</span><span class="n">API</span><span class="p">(</span><span class="n">auth</span><span class="p">)</span>
<span class="c1" style="color: #408080; font-style: italic;">## This function sends the tweets. It will check the length of them first of all. </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">sendTweet</span><span class="p">(</span><span class="n">tweetText</span><span class="p">):</span>
<span class="n">randomNumber</span> <span class="o" style="color: #666666;">=</span> <span class="n">random</span><span class="o" style="color: #666666;">.</span><span class="n">randrange</span><span class="p">(</span><span class="mi" style="color: #666666;">4</span><span class="p">)</span> <span class="c1" style="color: #408080; font-style: italic;">#number 0 - (randrange-1) use 4</span>
<span class="c1" style="color: #408080; font-style: italic;">#print (randomNumber) #Use for debugging</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">randomNumber</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #666666;">0</span><span class="p">:</span>
<span class="n">api</span><span class="o" style="color: #666666;">.</span><span class="n">update_status</span><span class="p">(</span><span class="n">status</span><span class="o" style="color: #666666;">=</span><span class="n">tweetText</span><span class="p">)</span>
<span class="c1" style="color: #408080; font-style: italic;">#print (tweetText) #Use for debugging</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="bp" style="color: green;">None</span>
<span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="bp" style="color: green;">None</span>
<span class="c1" style="color: #408080; font-style: italic;">## This function will print one of the random Tweets</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">randomTweet</span><span class="p">():</span>
<span class="k" style="color: green; font-weight: bold;">try</span><span class="p">:</span>
<span class="n">tweetFile</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: green;">open</span><span class="p">(</span><span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">path</span><span class="o" style="color: #666666;">.</span><span class="n">join</span><span class="p">(</span><span class="n">FILEPATH</span><span class="p">,</span><span class="s1" style="color: #ba2121;">'Tweets.txt'</span><span class="p">),</span><span class="s1" style="color: #ba2121;">'r'</span><span class="p">)</span>
<span class="n">tweetList</span> <span class="o" style="color: #666666;">=</span> <span class="n">tweetFile</span><span class="o" style="color: #666666;">.</span><span class="n">readlines</span><span class="p">()</span>
<span class="n">tweetFile</span><span class="o" style="color: #666666;">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">randomChoice</span> <span class="o" style="color: #666666;">=</span> <span class="n">random</span><span class="o" style="color: #666666;">.</span><span class="n">randrange</span><span class="p">(</span><span class="nb" style="color: green;">len</span><span class="p">(</span><span class="n">tweetList</span><span class="p">))</span>
<span class="c1" style="color: #408080; font-style: italic;">#print (tweetList[randomChoice]) #For debugging only</span>
<span class="n">sendTweet</span><span class="p">(</span><span class="n">tweetList</span><span class="p">[</span><span class="n">randomChoice</span><span class="p">])</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="bp" style="color: green;">None</span>
<span class="k" style="color: green; font-weight: bold;">except</span> <span class="ne" style="color: #d2413a; font-weight: bold;">IOError</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="bp" style="color: green;">None</span>
<span class="n">randomTweet</span><span class="p">()</span></pre>
<br />
Now in order to get started with this you will need to do two things.<br />
<br />
1. Install Tweepy.<br />
2. Create an app on Twitter<br />
<br />
I am not going to explain either of these processes, as I learned how to do this from another blog by the wonderful <a href="http://raspi.tv/">Raspi.tv</a>. They have done a far better job than I could ever do on this, so please go and read this blog on setting up Tweepy, and then come back to me. :-)<br />
<br />
The link you need to follow is here:<br />
<br />
<a href="http://raspi.tv/2013/how-to-create-a-twitter-app-on-the-raspberry-pi-with-python-tweepy-part-1#app">http://raspi.tv/2013/how-to-create-a-twitter-app-on-the-raspberry-pi-with-python-tweepy-part-1#app</a><br />
<br />
Right, you are back? Good!<br />
<br />
So the first lines of code call in some libraries including Tweepy, which should now be installed on your Raspberry Pi.<br />
<br />
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: green; font-weight: bold;">from</span> <span class="nn" style="color: blue; font-weight: bold;">__future__</span> <span class="kn" style="color: green; font-weight: bold;">import</span> <span class="n">print_function</span> <span class="c1" style="color: #408080; font-style: italic;">#Allows python3 use of print()</span>
<span class="kn" style="color: green; font-weight: bold;">import</span> <span class="nn" style="color: blue; font-weight: bold;">random</span>
<span class="kn" style="color: green; font-weight: bold;">import</span> <span class="nn" style="color: blue; font-weight: bold;">string</span>
<span class="kn" style="color: green; font-weight: bold;">import</span> <span class="nn" style="color: blue; font-weight: bold;">tweepy</span>
<span class="kn" style="color: green; font-weight: bold;">import</span> <span class="nn" style="color: blue; font-weight: bold;">os</span></pre>
<br />
The first line allows us to use the Python 3 version of print, which is something I am trying to do a little more these days. The next 4 lines all call libraries we need to use.<br />
<br />
The next line caused me the most problems. When you run your program using cron (more on this later), your program needs to know exactly where to go looking for any files you call. Normally I would be in the current directory when I run this program, so this line would not matter. When you run your program using cron it is starting from a different directory, so this line is necessary.<br />
<br />
If you don't know what cron is don't worry, it's not difficult. I will explain all later.<br />
<br />
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">FILEPATH</span> <span class="o" style="color: #666666;">=</span> <span class="s1" style="color: #ba2121;">'/home/pi/Desktop/TwitterBot'</span> </pre>
<br />
The path to my directory is /home/pi/Desktop/TwitterBot, but you will have to modify this line to suit your requirements.<br />
<br />
So how do you find out the location of your program? Well, you can navigate to it in the command line, and then type:<br />
<br />
<pre style="background: rgb(32, 32, 32); border-radius: 2px; border: 1px solid rgb(204, 204, 204); color: #d0d0d0; font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;">pwd</pre>
<br />
This will return the directory of where your files are. In my case I store them on the desktop in a folder called TwitterBot. We will use this information later in our program.<br />
<br />
So you read the blog post by Raspi.tv? You should therefore have been able to set up an app in twitter, and be able to fill out the information required in these lines of code.<br />
<div>
<br /></div>
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c1" style="color: #408080; font-style: italic;"># Consumer keys and access tokens, used for OAuth </span>
<span class="n">consumer_key</span> <span class="o" style="color: #666666;">=</span> <span class="s1" style="color: #ba2121;">'YourConsumerKey'</span>
<span class="n">consumer_secret</span> <span class="o" style="color: #666666;">=</span> <span class="s1" style="color: #ba2121;">'YourConsumerSecret'</span>
<span class="n">access_token</span> <span class="o" style="color: #666666;">=</span> <span class="s1" style="color: #ba2121;">'YourAccessToken'</span>
<span class="n">access_token_secret</span> <span class="o" style="color: #666666;">=</span> <span class="s1" style="color: #ba2121;">'YourAccessTokenSecret'</span>
<span class="c1" style="color: #408080; font-style: italic;"># OAuth process, using the keys and tokens</span>
<span class="n">auth</span> <span class="o" style="color: #666666;">=</span> <span class="n">tweepy</span><span class="o" style="color: #666666;">.</span><span class="n">OAuthHandler</span><span class="p">(</span><span class="n">consumer_key</span><span class="p">,</span> <span class="n">consumer_secret</span><span class="p">)</span>
<span class="n">auth</span><span class="o" style="color: #666666;">.</span><span class="n">set_access_token</span><span class="p">(</span><span class="n">access_token</span><span class="p">,</span> <span class="n">access_token_secret</span><span class="p">)</span>
<span class="c1" style="color: #408080; font-style: italic;"># Creation of the actual interface, using authentication</span>
<span class="n">api</span> <span class="o" style="color: #666666;">=</span> <span class="n">tweepy</span><span class="o" style="color: #666666;">.</span><span class="n">API</span><span class="p">(</span><span class="n">auth</span><span class="p">)</span></pre>
<br />
Ensure you replace the text in the first 4 lines with your consumer key, consumer secret, access token and access token secret. For your reference, if you just want a reminder of where to find all the information, you need to go to the twitter apps website.<br />
<br />
<a href="https://apps.twitter.com/">https://apps.twitter.com/</a><br />
<br />
That's all the difficult twitter stuff out of the way. There are just two functions we need to write. One chooses a random tweet, and one tweets it.<br />
<br />
Let us look at the function which sends the tweets.<br />
<br />
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c1" style="color: #408080; font-style: italic;">## This function sends the tweets. It will check the length of them first of all. </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">sendTweet</span><span class="p">(</span><span class="n">tweetText</span><span class="p">):</span>
<span class="n">randomNumber</span> <span class="o" style="color: #666666;">=</span> <span class="n">random</span><span class="o" style="color: #666666;">.</span><span class="n">randrange</span><span class="p">(</span><span class="mi" style="color: #666666;">4</span><span class="p">)</span> <span class="c1" style="color: #408080; font-style: italic;">#number 0 - (randrange-1) use 4</span>
<span class="c1" style="color: #408080; font-style: italic;">#print (randomNumber) #Use for debugging</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">randomNumber</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #666666;">0</span><span class="p">:</span>
<span class="n">api</span><span class="o" style="color: #666666;">.</span><span class="n">update_status</span><span class="p">(</span><span class="n">status</span><span class="o" style="color: #666666;">=</span><span class="n">tweetText</span><span class="p">)</span>
<span class="c1" style="color: #408080; font-style: italic;">#print (tweetText) #Use for debugging</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="bp" style="color: green;">None</span>
<span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="bp" style="color: green;">None</span> </pre>
<br />
The first line<br />
<br />
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">sendTweet</span><span class="p">(</span><span class="n">tweetText</span><span class="p">):</span></pre>
<br />
creates the function, but also expects some text, stored in a variable called tweetText, to be passed into it. It is the text in tweetText that we will be tweeting.<br />
<br />
So this function does two things. It sends the tweet, which is what you would expect, but not every time... I have added an element of randomness into this so it only tweets once in every four attempts. Why did I do this? Well I wanted to post tweets at four times during the day - Midnight, 6am, lunchtime and 6pm, using GMT. But I don't want to send a tweet every time. I think one tweet a day, on average, is enough to advertise my blog post. So if I use cron to potentially post four times a day, but reduce the chance of posting to one time in four, on average I will post once a day, but at one of the four pre-determined times. Hope that makes sense!<br />
<br />
I did this to make it look a little less like a Twitterbot, which would normally post the same time every day. It just mixes it up a little and means there is a chance for a reader from other time zones to see one of my posts.<br />
<br />
So that's what the first line does, it picks a random number from 0 to 3, and stores it in the variable randomNumber. You can increase or decrease the frequency by playing around with the number in random.randrange().<br />
<br />
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">randomNumber</span> <span class="o" style="color: #666666;">=</span> <span class="n">random</span><span class="o" style="color: #666666;">.</span><span class="n">randrange</span><span class="p">(</span><span class="mi" style="color: #666666;">4</span><span class="p">)</span></pre>
<br />
I then use an if statement to check if that number is == 0, which in our program will be once in every four attempts on average.<br />
<div>
<br /></div>
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">randomNumber</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #666666;">0</span><span class="p">:</span></pre>
<br />
If it is we then send a tweet made up of the text we passed to our function, which is stored in tweetText. This makes use of the Twitter API to send the tweet.<br />
<br />
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">api</span><span class="o" style="color: #666666;">.</span><span class="n">update_status</span><span class="p">(</span><span class="n">status</span><span class="o" style="color: #666666;">=</span><span class="n">tweetText</span><span class="p">)</span> </pre>
<br />
We then return from the function.<br />
<br />
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">return</span> <span class="bp" style="color: green;">None</span></pre>
<br />
If randomNumber is not equal to zero, the program will just return without doing anything.<br />
<br />
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="bp" style="color: green;">None</span></pre>
<br />
All very simple so far.<br />
<br />
The second function we need to write is randomTweet(). This chooses one of the random tweets to send to the sendTweet() function. The tweets it will be choosing from are stored in a text file called Tweets.txt.<br />
<br />
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c1" style="color: #408080; font-style: italic;">## This function will print one of the random Tweets</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">randomTweet</span><span class="p">():</span>
<span class="k" style="color: green; font-weight: bold;">try</span><span class="p">:</span>
<span class="n"> tweetFile</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: green;">open</span><span class="p">(</span><span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">path</span><span class="o" style="color: #666666;">.</span><span class="n">join</span><span class="p">(</span><span class="n">FILEPATH</span><span class="p">,</span><span class="s1" style="color: #ba2121;">'Tweets.txt'</span><span class="p">),</span><span class="s1" style="color: #ba2121;">'r'</span><span class="p">)</span>
<span class="n">tweetList</span> <span class="o" style="color: #666666;">=</span> <span class="n">tweetFile</span><span class="o" style="color: #666666;">.</span><span class="n">readlines</span><span class="p">()</span>
<span class="n">tweetFile</span><span class="o" style="color: #666666;">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">randomChoice</span> <span class="o" style="color: #666666;">=</span> <span class="n">random</span><span class="o" style="color: #666666;">.</span><span class="n">randrange</span><span class="p">(</span><span class="nb" style="color: green;">len</span><span class="p">(</span><span class="n">tweetList</span><span class="p">))</span>
<span class="c1" style="color: #408080; font-style: italic;">#print (tweetList[randomChoice]) #For debugging only</span>
<span class="n">sendTweet</span><span class="p">(</span><span class="n">tweetList</span><span class="p">[</span><span class="n">randomChoice</span><span class="p">])</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="bp" style="color: green;">None</span>
<span class="k" style="color: green; font-weight: bold;">except</span> <span class="ne" style="color: #d2413a; font-weight: bold;">IOError</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="bp" style="color: green;">None</span> </pre>
<br />
<br />
We start off by naming the function. As you will see from the empty brackets this function is not expecting anything to be passed into it.<br />
<br />
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">randomTweet</span><span class="p">():</span></pre>
<br />
We are going to use Try and Except in this function. I do this in case there is an error loading up the file as I don't want the program to crash if it cannot find the file it is trying to open.<br />
<br />
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">try</span><span class="p">:</span>
<span class="n">tweetFile</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: green;">open</span><span class="p">(</span><span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">path</span><span class="o" style="color: #666666;">.</span><span class="n">join</span><span class="p">(</span><span class="n">FILEPATH</span><span class="p">,</span><span class="s1" style="color: #ba2121;">'Tweets.txt'</span><span class="p">),</span><span class="s1" style="color: #ba2121;">'r'</span><span class="p">)</span>
<span class="n">tweetList</span> <span class="o" style="color: #666666;">=</span> <span class="n">tweetFile</span><span class="o" style="color: #666666;">.</span><span class="n">readlines</span><span class="p">()</span>
<span class="n">tweetFile</span><span class="o" style="color: #666666;">.</span><span class="n">close</span><span class="p">()</span></pre>
<br />
So we Try the following.<br />
<br />
We open the file Tweets.txt and store the contents in the variable tweetFile. But as I mentioned earlier when we come to run cron, we need to give the full path to this file. So we use this command<br />
<div>
<br /></div>
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="p">(</span><span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">path</span><span class="o" style="color: #666666;">.</span><span class="n">join</span><span class="p">(</span><span class="n">FILEPATH</span><span class="p">,</span><span class="s1" style="color: #ba2121;">'Tweets.txt'</span><span class="p">)</span></pre>
<br />
to join Tweets.txt onto the filepath stored in FILEPATH. The reason I have stored the filepath in FILEPATH, is if I want to change it in the future, I only have to modify it in one place. That place is at the top of the program, so easy to find!<br />
<br />
We then store the contents of tweetFile into tweetList using readlines. This separates the text into a list which stores each line as a different item in the list.<br />
<div>
<br /></div>
<div>
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">tweetList</span> <span class="o" style="color: #666666;">=</span> <span class="n">tweetFile</span><span class="o" style="color: #666666;">.</span><span class="n">readlines</span><span class="p">()</span></pre>
</div>
<br />
Finally we close the open text file.<br />
<br />
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">tweetFile</span><span class="o" style="color: #666666;">.</span><span class="n">close</span><span class="p">()</span></pre>
<div>
<span class="p"><br /></span></div>
We then analyse the length of our list, and pick a random number from 0 to the length of the list. The result is stored in randomChoice.<br />
<br />
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">randomChoice</span> <span class="o" style="color: #666666;">=</span> <span class="n">random</span><span class="o" style="color: #666666;">.</span><span class="n">randrange</span><span class="p">(</span><span class="nb" style="color: green;">len</span><span class="p">(</span><span class="n">tweetList</span><span class="p">))</span></pre>
<br />
And then we send the item which is in that random location in the list to the function we wrote earlier called sendTweet.<br />
<br />
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">sendTweet</span><span class="p">(</span><span class="n">tweetList</span><span class="p">[</span><span class="n">randomChoice</span><span class="p">])</span></pre>
<br />
Then we return None<br />
<br />
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">return</span> <span class="bp" style="color: green;">None</span></pre>
<br />
Finally if there was an error in our try part of the function we catch it and just return from the function doing nothing.<br />
<br />
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">except</span> <span class="ne" style="color: #d2413a; font-weight: bold;">IOError</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="bp" style="color: green;">None</span> </pre>
<br />
Ok so far so good? Anything missing?<br />
<br />
Well if we don't call a function in our program then nothing will run. So we just call the function randomTweet() to kick things off the ground.<br />
<div>
<br /></div>
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: consolas, 'dejavu sans mono', 'bitstream vera sans mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">randomTweet</span><span class="p">()</span></pre>
<br />
And that is that, the programming is complete. There really is nothing tricky in all of this.<br />
<br />
But if you want this program to tweet we are not quite finished. There are two things remaining. You need to create a text file called Tweets.txt and store this in the same folder as your program. This text file should have each tweet you want to send on a different line in the text file, as shown below.<br />
<div>
<br /></div>
<pre style="background: rgb(248, 248, 248); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;">Tweet 1
Tweet 2
Tweet 3
Tweet 4
Tweet 5</pre>
<br />
Finally while we have our python program completed, and our Tweets.txt file created, we need some method of telling our Raspberry Pi to run it when we want it to be run.<br />
<br />
This is where the wonderful tool called cron comes into its own.<br />
<br />
In the past I have written <a href="http://trevorappleton.blogspot.co.uk/2014/06/scheduling-python-programs-using-cron.html" target="_blank">a blog post explaining how cron works</a>. Definitely worth a read. But if you just want to get on and get your Twitterbot underway then I will explain what you need to do.<br />
<br />
I said earlier that I would like my Twitterbot to (potentially) tweet 4 times a day. I say potentially as there is randomness in the the code to ensure it only tweets one in four times. To tell the Raspberry Pi to try to tweet at four times in the day I will have to add four lines of code to my crontab file.<br />
<br />
On your Raspberry Pi you need to open a terminal window and type<br />
<br />
<pre style="background: rgb(32, 32, 32); border-radius: 2px; border: 1px solid rgb(204, 204, 204); color: #d0d0d0; font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;">Crontab -e</pre>
<br />
This will open up the file you need to modify, probably using a text editor called nano.<br />
<br />
You will need to enter the following text at the bottom of this:<br />
<div>
<br /></div>
<pre style="background: rgb(32, 32, 32); border-radius: 2px; border: 1px solid rgb(204, 204, 204); color: #d0d0d0; font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;">00 00 * * * /usr/bin/python /home/pi/Desktop/TwitterBot/TwitterBot.py
00 06 * * * /usr/bin/python /home/pi/Desktop/TwitterBot/TwitterBot.py
00 12 * * * /usr/bin/python /home/pi/Desktop/TwitterBot/TwitterBot.py
00 18 * * * /usr/bin/python /home/pi/Desktop/TwitterBot/TwitterBot.py</pre>
<br />
A brief explanation of each of these lines is as follows:<br />
<ul>
<li>For each of the lines the first 00 refers to the minutes past the hour we want our program to run. </li>
<li>00,06,12,18 refer to the hour, (24 hour format) at which we want the program to run. </li>
<li>* * * refer to day of Month, Month and Day of week respectively. We want to ignore all these, so use a * for each. </li>
<li>The /usr/bin/python explains you want to launch your program with python. </li>
<li>/home/pi/Desktop/TwitterBot/TwitterBot.py gives the full path to the program you want to run. </li>
</ul>
<br />
Press ctrl-x and follow the instructions to save and exit.<br />
<br />
And that is that. You have a fully functioning Twitterbot which will try to tweet 4 times a day, but on average will only manage it once :-)<br />
<br />
I hope this has given you the basics of turning your Raspberry Pi into a Twitterbot. Let me know what Twitterbots you create!Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com5tag:blogger.com,1999:blog-8250429656532783188.post-60144897207990874932016-01-06T20:28:00.003+00:002016-01-06T20:28:24.833+00:00Turn your Raspberry Pi into an Audiophile Music PlayerSo my younger brother came to stay recently and asked me to give him a hand to do something with his Raspberry Pi. Always eager to help out with all things Raspberry Pi related, I had a look into what he wanted to do.<br />
<br />
He told me he wanted to set up Volumio. I have to admit I had never heard of Volumio, but by the time we were finished setting it up, I was sold! It is very cool! What's more it was so easy to set up! Almost too easy to warrant a blog post...<br />
<br />
However - where is the fun in that?<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://cdn.volumio.org/wp-content/uploads/2013/11/logo1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="42" src="https://cdn.volumio.org/wp-content/uploads/2013/11/logo1.png" width="320" /></a></div>
<br />
<br />
So what is Volumio? Well Volumio calls itself a Linux Audiophile Music Player. Basically it turns your Raspberry Pi, or many other devices, into a Music Player. You can simply add a USB stick with your music on it, and Volumio will play it. The great thing is you control the music remotely, so don't need anything other than a speaker/headphones connected to your Raspberry Pi.<br />
<br />
So first of all you will need to download Volumio. Go to their website, and click on Download.<br />
<br />
<div style="text-align: center;">
<a href="https://volumio.org/project/">https://volumio.org/project/</a></div>
<br />
Once the download is completed you need to flash it onto a suitable SD Card. I am assuming that you already know how to do this, but if not, there are instructions on the Volumio web site on how to do this using either Linux, MacOSX or Windows. It's the same method as you would load any Linux distribution onto a SD Card.<br />
<br />
For the purposes of trying this out, I am using a 4GB card. However Volumio is fairly small so has no problem fitting on a card that size.<br />
<br />
Once that is done put the newly created SD card into your Raspberry Pi and fire it up! At this point you will need to have your Raspberry Pi connected to your router via an ethernet cable. We will sort out going wireless later.<br />
<br />
Open an internet browser on your computer, and go to the following link:<br />
<br />
<div style="text-align: center;">
<a href="http://volumio.local/">http://volumio.local/</a></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
Your screen should look something like this. </div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyozet6qIqpFQPR7Cer9zjr-fnfmkqoUxXmMTEl_uqajbvvVtGWL5tjJMArWTF0c03uilZCRyPwUfAJZRVYIgHufTw_RBGd1ukWLfwuyoqcPaV2HUvX7LesSHfNVL4kRneotTk5kXMwQY/s1600/Screen+Shot+2016-01-04+at+21.54.56.png" imageanchor="1"><img border="0" height="448" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyozet6qIqpFQPR7Cer9zjr-fnfmkqoUxXmMTEl_uqajbvvVtGWL5tjJMArWTF0c03uilZCRyPwUfAJZRVYIgHufTw_RBGd1ukWLfwuyoqcPaV2HUvX7LesSHfNVL4kRneotTk5kXMwQY/s640/Screen+Shot+2016-01-04+at+21.54.56.png" width="640" /></a></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
How easy was that? </div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
However there is no point having an Audiophile Music Player without any music to play.<br />
<br />
The next thing you need to do is to put some music onto a USB stick, and insert this into your Raspberry Pi. You might notice the bottom left of the screen indicates it is Updating. This takes a few minutes depending on how many songs you have on the USB stick.<br />
<br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6LQkkgQbi7Vq7qQH_DdvQkfEp_mZkH5lV0VI0iny4sSBhYKHERFjNm0OJZYwq-f0M6AAcae2b7XxBQfvge7auHpGoDX4vWVfFdZld3zKsvbhe9YLasxLLtKsScBUBNxh3fTSTiXbo1EU/s1600/Screen+Shot+2016-01-05+at+20.26.56.png" imageanchor="1"><img border="0" height="32" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6LQkkgQbi7Vq7qQH_DdvQkfEp_mZkH5lV0VI0iny4sSBhYKHERFjNm0OJZYwq-f0M6AAcae2b7XxBQfvge7auHpGoDX4vWVfFdZld3zKsvbhe9YLasxLLtKsScBUBNxh3fTSTiXbo1EU/s320/Screen+Shot+2016-01-05+at+20.26.56.png" width="320" /></a></div>
<br />
<br />
Once completed this will resort back to saying Browse.<br />
<br />
Plug your Headphones / Speaker into the Headphone Port of your Raspberry Pi. On older Raspberry Pi's this is the blue port, or on a Raspberry Pi 2 the port next to the HDMI port.<br />
<br />
Now click on Browse and then on USB, and then follow your filing system on your USB stick until you find the song you want to play and double click on it.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzSfJuw04wwCr7-DPiTX8kNQ64liZiO1ZU-2UOvXWXalHp4WHRwlWcuAybxceTgIx6qEGswRMPYM1a3tAqFEpldbL7_j7Pqf3TtjeCBKXoErzVqRidz7ZACmQJsuo0mAKSUXO2qU0Arfo/s1600/Screen+Shot+2016-01-05+at+20.48.10.png" imageanchor="1"><img border="0" height="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzSfJuw04wwCr7-DPiTX8kNQ64liZiO1ZU-2UOvXWXalHp4WHRwlWcuAybxceTgIx6qEGswRMPYM1a3tAqFEpldbL7_j7Pqf3TtjeCBKXoErzVqRidz7ZACmQJsuo0mAKSUXO2qU0Arfo/s640/Screen+Shot+2016-01-05+at+20.48.10.png" width="640" /></a><br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br /></div>
<div style="text-align: left;">
Here I chose the Cantina Band from the Star Wars album. A message will appear saying you have added it to the playlist. It should start playing immediately.<br />
<br />
Selecting other songs will add them to the play list also. Click on Playlist at the bottom to view the Playlist you have created.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8zqDculaKQEcRNfsG6Hof3mSLMYIUdbZz4575TqGLwAzpT87NedZGOVr3YWQmvTDWVAqPqj6aLnFcjZbDitlrXiHAqUt59tGtZyWk_4WpeqoEMXL9Jxu__57y16yLn2OK1_mOm7S4q50/s1600/Screen+Shot+2016-01-05+at+20.51.58.png" imageanchor="1"><img border="0" height="144" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8zqDculaKQEcRNfsG6Hof3mSLMYIUdbZz4575TqGLwAzpT87NedZGOVr3YWQmvTDWVAqPqj6aLnFcjZbDitlrXiHAqUt59tGtZyWk_4WpeqoEMXL9Jxu__57y16yLn2OK1_mOm7S4q50/s640/Screen+Shot+2016-01-05+at+20.51.58.png" width="640" /></a><br />
<br />
The Playback menu allows you to see what is playing and change the volume etc.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGk6eFB0IJQmvrxYQoqawLQj7X3igISUwSPg9i3OXRzK2svMDiQNknXp0cwKogQDGjw2DR1-68oG8r4-PFarGqHstjNHiahKxzeAl1bLH7P8BW8f0YM4eSRDEw3iU3IwjsALg56rcyyF0/s1600/Screen+Shot+2016-01-05+at+20.53.04.png" imageanchor="1"><img border="0" height="428" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGk6eFB0IJQmvrxYQoqawLQj7X3igISUwSPg9i3OXRzK2svMDiQNknXp0cwKogQDGjw2DR1-68oG8r4-PFarGqHstjNHiahKxzeAl1bLH7P8BW8f0YM4eSRDEw3iU3IwjsALg56rcyyF0/s640/Screen+Shot+2016-01-05+at+20.53.04.png" width="640" /></a><br />
<br />
It really is so simple and intuitive to use!<br />
<br />
Want to listen to internet radio? Instead of clicking on USB, you can click on Web Radio. There are a number of pre-defined radio stations.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbL-2OdtaF84qmVkuy_rTXJb90su_dXUC7LQ1TGqFJKQMMmTcsazizsJ7ZbGB-WF_-Lx74Twn3-20S3JNXXsShBRwtcvd8mgSs6_na2oSaq7JStBTGoZeZ6zbMj29hPy2BWnaBxnADzmg/s1600/Screen+Shot+2016-01-05+at+21.15.32.png" imageanchor="1"><img border="0" height="432" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbL-2OdtaF84qmVkuy_rTXJb90su_dXUC7LQ1TGqFJKQMMmTcsazizsJ7ZbGB-WF_-Lx74Twn3-20S3JNXXsShBRwtcvd8mgSs6_na2oSaq7JStBTGoZeZ6zbMj29hPy2BWnaBxnADzmg/s640/Screen+Shot+2016-01-05+at+21.15.32.png" width="640" /></a><br />
<br />
<br />
Earlier I mentioned that you can set this up so it works over WiFi. I use an Edimax EW-7811UN Dongle, but I have also tested this with a Wi-Pi dongle and they both work equally well. You can pick these up cheaply on the internet.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgr9gDl_kKPk5inmbGpTQQwAWiybuotkpjR7pxqIWmAWpH8_iMR888h-8SqsHjik6saUh9R6iTukq7GemzmJsYSrQswlwpqSMHOhcoH0jad2suSM-g9mbVapJUR5CK4MhI-ZuWSd6s-U_k/s1600/EDIMAX_EW-7811UN_01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgr9gDl_kKPk5inmbGpTQQwAWiybuotkpjR7pxqIWmAWpH8_iMR888h-8SqsHjik6saUh9R6iTukq7GemzmJsYSrQswlwpqSMHOhcoH0jad2suSM-g9mbVapJUR5CK4MhI-ZuWSd6s-U_k/s400/EDIMAX_EW-7811UN_01.jpg" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
To set this up click on Menu and then Network.<br />
<br />
Type in your Network Name, for me this is Spongebob (Don't judge me - ok?), the type of security you have, along with your password.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizHX1YWcRywL4oDudgIeYSI9_QMWG2ogkOVquzAbKxSxfu78JY3bESwhnEQVM5oljNXAYwFWpQZjytSQUo_-pEUby0rGe9l-TPKq5jOw70bOVlTgfyZGQOmUFeGiYY9lQqGxcRbDe_3SA/s1600/Screen+Shot+2016-01-05+at+21.03.54.png" imageanchor="1"><img border="0" height="374" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizHX1YWcRywL4oDudgIeYSI9_QMWG2ogkOVquzAbKxSxfu78JY3bESwhnEQVM5oljNXAYwFWpQZjytSQUo_-pEUby0rGe9l-TPKq5jOw70bOVlTgfyZGQOmUFeGiYY9lQqGxcRbDe_3SA/s640/Screen+Shot+2016-01-05+at+21.03.54.png" width="640" /></a><br />
<br /></div>
<div style="text-align: left;">
Finally click on Save Changes. They may take a few minutes to save. However once finished you should see your Edimax Blue LED Light up.<br />
<br />
You can now remove your network cable, and be connected wirelessly.<br />
<br />
And there you have it, your Raspberry Pi is a fully functioning Jukebox!<br />
<br />
<div style="margin-bottom: .0001pt; margin: 0cm;">
Take Volumio a step further and download an app, so you can
control your music selections using your phone or tablet. Enjoy!</div>
<br /></div>
Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com3tag:blogger.com,1999:blog-8250429656532783188.post-64553246923896396482015-09-02T19:37:00.000+01:002015-09-02T19:38:38.089+01:00Solving Peg Solitaire using Depth First Search in PythonI am a huge fan of puzzles, and think that my love of programming comes from that enjoyment. There is something hugely satisfying about finding the solution to a puzzle.<br />
<br />
One of my earlier forays into solving a puzzle using Python was to solve the Rubiks cube. I, naively, thought it would be a simple matter to churn through all the available options until the program stumbled across the solution.<br />
<br />
I made great progress with it... and then I started to research how difficult a task it really was. There were billions of solutions. Finally I realised Google had thrown their weight behind the puzzle, and determined the 'god' number. This is the minimum number of moves needed to solve a Rubiks cube from any position. It turns out the god number is 20.<br />
<br />
At this point I put the Python solution for the Rubiks cube aside, at least temporarily. It turned out just learning how to actually do the Rubiks cube is much easier than you think! However, in the process, I had learnt a little about Breadth-first search and Depth-first search, and thought it would be great to solve a problem using one of these methods. More for my knowledge than anything else.<br />
<br />
My son started to play with Pin Solitaire at a friends house one day, and I gave him a hand explaining the game. It's one of those things I have played with every so often, but never really tried to work out. This would be an ideal puzzle to solve using Python.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Solitaire_01.jpg/225px-Solitaire_01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Solitaire_01.jpg/225px-Solitaire_01.jpg" /></a></div>
<br />
<br />
Surely it must be quite easy in comparison to the Rubiks cube!<br />
<br />
To solve this problem, I used Depth-first search. It would be equally possible with Breadth-first search, it's just I was more interested in using the Depth-first search algorithm.<br />
<br />
I am not going to go into great detail on Depth vs Breadth-first search. That may have to be basis of another blog post :-)<br />
<br />
However Depth-first follows one potential solution until it finds a solution or reaches a dead end. At this point it then backtracks until there is another option available, which it follows to the end. So on and so forth until all options have been exhausted.<br />
<br />
Breadth-first search would try out all the possible options available after just one move. It would then try out all the possible second moves, then the third moves etc. until the puzzle was solved.<br />
<br />
If you are interested in researching a little more on this topic you can read more about both options here.<br />
<br />
<div style="text-align: left;">
<a href="https://en.wikipedia.org/wiki/Depth-first_search" target="_blank">Depth First Search (DFS)</a></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<a href="https://en.wikipedia.org/wiki/Breadth-first_search" target="_blank">Breadth First Search (BFS)</a></div>
<br />
First of all I am going to show you my program in its entirety, and then take you through the programming of it line by line.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: #007020; font-weight: bold;">from</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">__future__</span> <span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="n">print_function</span> <span class="c" style="color: #60a0b0; font-style: italic;">#Allows python3 use of print()</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">copy</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">datetime</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Global Constants</span>
<span class="n">WIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">7</span>
<span class="n">HEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">7</span>
<span class="n">CORNERSIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Global Variables</span>
<span class="n">gameBoard</span> <span class="o" style="color: #666666;">=</span> <span class="p">{}</span>
<span class="n">storeBoards</span> <span class="o" style="color: #666666;">=</span> <span class="p">[]</span>
<span class="n">solutionCount</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="c" style="color: #60a0b0; font-style: italic;">## Functions</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Setup Fully Populated Board</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">setupSolitaire</span><span class="p">(</span><span class="n">board</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">y</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span> <span class="p">(</span><span class="n">HEIGHT</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span> <span class="p">(</span><span class="n">WIDTH</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="p">((</span><span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="n">CORNERSIZE</span><span class="p">)</span> <span class="ow" style="color: #007020; font-weight: bold;">or</span> <span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="n">WIDTH</span><span class="o" style="color: #666666;">-</span><span class="n">CORNERSIZE</span><span class="p">,</span><span class="n">WIDTH</span><span class="p">))</span>
<span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="p">(</span><span class="n">y</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="n">CORNERSIZE</span><span class="p">)</span> <span class="ow" style="color: #007020; font-weight: bold;">or</span> <span class="n">y</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="n">HEIGHT</span><span class="o" style="color: #666666;">-</span><span class="n">CORNERSIZE</span><span class="p">,</span><span class="n">HEIGHT</span><span class="p">))):</span>
<span class="n">board</span><span class="p">[</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">' '</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">x</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">WIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">2</span><span class="p">)</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">y</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">HEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">2</span><span class="p">):</span>
<span class="n">board</span><span class="p">[</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">board</span><span class="p">[</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'X'</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">board</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">setupCross</span><span class="p">(</span><span class="n">board</span><span class="p">):</span>
<span class="n">board</span> <span class="o" style="color: #666666;">=</span> <span class="n">setupSolitaire</span><span class="p">(</span><span class="n">board</span><span class="p">)</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'X'</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">board</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">setupPlus</span><span class="p">(</span><span class="n">board</span><span class="p">):</span>
<span class="n">board</span> <span class="o" style="color: #666666;">=</span> <span class="n">setupSolitaire</span><span class="p">(</span><span class="n">board</span><span class="p">)</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'X'</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">board</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">setupFireplace</span><span class="p">(</span><span class="n">board</span><span class="p">):</span>
<span class="n">board</span> <span class="o" style="color: #666666;">=</span> <span class="n">setupSolitaire</span><span class="p">(</span><span class="n">board</span><span class="p">)</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">board</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">setupPyramid</span><span class="p">(</span><span class="n">board</span><span class="p">):</span>
<span class="n">board</span> <span class="o" style="color: #666666;">=</span> <span class="n">setupSolitaire</span><span class="p">(</span><span class="n">board</span><span class="p">)</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'X'</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">board</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">setupArrow</span><span class="p">(</span><span class="n">board</span><span class="p">):</span>
<span class="n">board</span> <span class="o" style="color: #666666;">=</span> <span class="n">setupSolitaire</span><span class="p">(</span><span class="n">board</span><span class="p">)</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'X'</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">board</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">setupDiamond</span><span class="p">(</span><span class="n">board</span><span class="p">):</span>
<span class="n">board</span> <span class="o" style="color: #666666;">=</span> <span class="n">setupSolitaire</span><span class="p">(</span><span class="n">board</span><span class="p">)</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'X'</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">board</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">printBoard</span><span class="p">(</span><span class="n">board</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">y</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span> <span class="p">(</span><span class="n">HEIGHT</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span> <span class="p">(</span><span class="n">WIDTH</span><span class="p">):</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#print (board[x,y], end = " ") #The end prevents new lines being printed </span>
<span class="n">outFile</span><span class="o" style="color: #666666;">.</span><span class="n">writelines</span><span class="p">(</span><span class="n">board</span><span class="p">[</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">])</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#print ('\n')</span>
<span class="n">outFile</span><span class="o" style="color: #666666;">.</span><span class="n">writelines</span><span class="p">(</span><span class="s" style="color: #4070a0;">'</span><span class="se" style="color: #4070a0; font-weight: bold;">\n</span><span class="s" style="color: #4070a0;">'</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#print ('\n')</span>
<span class="n">outFile</span><span class="o" style="color: #666666;">.</span><span class="n">writelines</span><span class="p">(</span><span class="s" style="color: #4070a0;">'</span><span class="se" style="color: #4070a0; font-weight: bold;">\n</span><span class="s" style="color: #4070a0;">'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">checkResult</span><span class="p">(</span><span class="n">board</span><span class="p">):</span>
<span class="n">count</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">board</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">board</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="s" style="color: #4070a0;">'X'</span><span class="p">:</span>
<span class="n">count</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">count</span> <span class="o" style="color: #666666;">></span><span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">False</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span><span class="c" style="color: #60a0b0; font-style: italic;"># The count must be 1</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">True</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">listPossibleMoves</span><span class="p">(</span><span class="n">gameBoard</span><span class="p">,</span><span class="n">solutionCount</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">checkResult</span><span class="p">(</span><span class="n">gameBoard</span><span class="p">)</span> <span class="o" style="color: #666666;">==</span> <span class="bp" style="color: #007020;">True</span><span class="p">:</span>
<span class="n">outFile</span><span class="o" style="color: #666666;">.</span><span class="n">writelines</span><span class="p">(</span><span class="s" style="color: #4070a0;">'Start Solution</span><span class="se" style="color: #4070a0; font-weight: bold;">\n\n</span><span class="s" style="color: #4070a0;">'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">storeBoards</span><span class="p">:</span>
<span class="n">printBoard</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
<span class="n">outFile</span><span class="o" style="color: #666666;">.</span><span class="n">writelines</span><span class="p">(</span><span class="s" style="color: #4070a0;">'End Solution</span><span class="se" style="color: #4070a0; font-weight: bold;">\n\n</span><span class="s" style="color: #4070a0;">'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">solutionCount</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">gameBoard</span><span class="p">:</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Check if piece can move in + X</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;"><</span> <span class="p">(</span><span class="n">WIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="mi" style="color: #40a070;">2</span><span class="p">)</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'X'</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'O'</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'X'</span><span class="p">:</span>
<span class="n">new</span> <span class="o" style="color: #666666;">=</span> <span class="n">copy</span><span class="o" style="color: #666666;">.</span><span class="n">deepcopy</span><span class="p">(</span><span class="n">gameBoard</span><span class="p">)</span>
<span class="n">new</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">new</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]]</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">'X'</span>
<span class="n">new</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]]</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">'O'</span>
<span class="n">solutionCount</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="p">(</span><span class="n">solutionCount</span> <span class="o" style="color: #666666;">%</span> <span class="mi" style="color: #40a070;">1000000</span><span class="p">)</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">0</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="p">(</span><span class="n">solutionCount</span><span class="p">,</span><span class="s" style="color: #4070a0;">'solutionCount'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">new</span> <span class="ow" style="color: #007020; font-weight: bold;">not</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">storeBoards</span><span class="p">:</span>
<span class="n">storeBoards</span><span class="o" style="color: #666666;">.</span><span class="n">append</span><span class="p">(</span><span class="n">new</span><span class="p">)</span>
<span class="n">solutionCount</span> <span class="o" style="color: #666666;">=</span> <span class="n">listPossibleMoves</span><span class="p">(</span><span class="n">new</span><span class="p">,</span><span class="n">solutionCount</span><span class="p">)</span>
<span class="n">storeBoards</span><span class="o" style="color: #666666;">.</span><span class="n">remove</span><span class="p">(</span><span class="n">new</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Check if piece can move in - X</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">></span> <span class="p">(</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'X'</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'O'</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'X'</span><span class="p">:</span>
<span class="n">new</span> <span class="o" style="color: #666666;">=</span> <span class="n">copy</span><span class="o" style="color: #666666;">.</span><span class="n">deepcopy</span><span class="p">(</span><span class="n">gameBoard</span><span class="p">)</span>
<span class="n">new</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">new</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]]</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">'X'</span>
<span class="n">new</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]]</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">'O'</span>
<span class="n">solutionCount</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="p">(</span><span class="n">solutionCount</span> <span class="o" style="color: #666666;">%</span> <span class="mi" style="color: #40a070;">1000000</span><span class="p">)</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">0</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="p">(</span><span class="n">solutionCount</span><span class="p">,</span><span class="s" style="color: #4070a0;">'solutionCount'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">new</span> <span class="ow" style="color: #007020; font-weight: bold;">not</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">storeBoards</span><span class="p">:</span>
<span class="n">storeBoards</span><span class="o" style="color: #666666;">.</span><span class="n">append</span><span class="p">(</span><span class="n">new</span><span class="p">)</span>
<span class="n">solutionCount</span> <span class="o" style="color: #666666;">=</span> <span class="n">listPossibleMoves</span><span class="p">(</span><span class="n">new</span><span class="p">,</span><span class="n">solutionCount</span><span class="p">)</span>
<span class="n">storeBoards</span><span class="o" style="color: #666666;">.</span><span class="n">remove</span><span class="p">(</span><span class="n">new</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Check if piece can move in + Y</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;"><</span> <span class="p">(</span><span class="n">HEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="mi" style="color: #40a070;">2</span><span class="p">)</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'X'</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">],</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'O'</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">],</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'X'</span><span class="p">:</span>
<span class="n">new</span> <span class="o" style="color: #666666;">=</span> <span class="n">copy</span><span class="o" style="color: #666666;">.</span><span class="n">deepcopy</span><span class="p">(</span><span class="n">gameBoard</span><span class="p">)</span>
<span class="n">new</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">new</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">],</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">'X'</span>
<span class="n">new</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">],</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">'O'</span>
<span class="n">solutionCount</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="p">(</span><span class="n">solutionCount</span> <span class="o" style="color: #666666;">%</span> <span class="mi" style="color: #40a070;">1000000</span><span class="p">)</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">0</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="p">(</span><span class="n">solutionCount</span><span class="p">,</span><span class="s" style="color: #4070a0;">'solutionCount'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">new</span> <span class="ow" style="color: #007020; font-weight: bold;">not</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">storeBoards</span><span class="p">:</span>
<span class="n">storeBoards</span><span class="o" style="color: #666666;">.</span><span class="n">append</span><span class="p">(</span><span class="n">new</span><span class="p">)</span>
<span class="n">solutionCount</span> <span class="o" style="color: #666666;">=</span> <span class="n">listPossibleMoves</span><span class="p">(</span><span class="n">new</span><span class="p">,</span><span class="n">solutionCount</span><span class="p">)</span>
<span class="n">storeBoards</span><span class="o" style="color: #666666;">.</span><span class="n">remove</span><span class="p">(</span><span class="n">new</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Check if piece can move in - Y</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">></span> <span class="p">(</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'X'</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">],</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'O'</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">],</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'X'</span><span class="p">:</span>
<span class="n">new</span> <span class="o" style="color: #666666;">=</span> <span class="n">copy</span><span class="o" style="color: #666666;">.</span><span class="n">deepcopy</span><span class="p">(</span><span class="n">gameBoard</span><span class="p">)</span>
<span class="n">new</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">new</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">],</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">'X'</span>
<span class="n">new</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">],</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">'O'</span>
<span class="n">solutionCount</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="p">(</span><span class="n">solutionCount</span> <span class="o" style="color: #666666;">%</span> <span class="mi" style="color: #40a070;">1000000</span><span class="p">)</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">0</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="p">(</span><span class="n">solutionCount</span><span class="p">,</span><span class="s" style="color: #4070a0;">'solutionCount'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">new</span> <span class="ow" style="color: #007020; font-weight: bold;">not</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">storeBoards</span><span class="p">:</span>
<span class="n">storeBoards</span><span class="o" style="color: #666666;">.</span><span class="n">append</span><span class="p">(</span><span class="n">new</span><span class="p">)</span>
<span class="n">solutionCount</span> <span class="o" style="color: #666666;">=</span> <span class="n">listPossibleMoves</span><span class="p">(</span><span class="n">new</span><span class="p">,</span><span class="n">solutionCount</span><span class="p">)</span>
<span class="n">storeBoards</span><span class="o" style="color: #666666;">.</span><span class="n">remove</span><span class="p">(</span><span class="n">new</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">solutionCount</span>
<span class="n">startTime</span> <span class="o" style="color: #666666;">=</span> <span class="n">datetime</span><span class="o" style="color: #666666;">.</span><span class="n">datetime</span><span class="o" style="color: #666666;">.</span><span class="n">now</span><span class="p">()</span>
<span class="n">outFile</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">open</span> <span class="p">(</span><span class="s" style="color: #4070a0;">'result.txt'</span><span class="p">,</span><span class="s" style="color: #4070a0;">'w'</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#gameBoard = setupSolitaire(gameBoard)</span>
<span class="n">gameBoard</span> <span class="o" style="color: #666666;">=</span> <span class="n">setupCross</span><span class="p">(</span><span class="n">gameBoard</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#gameBoard = setupPlus(gameBoard)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#gameBoard = setupFireplace(gameBoard)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#gameBoard = setupPyramid(gameBoard)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#gameBoard = setupArrow(gameBoard)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#gameBoard = setupDiamond(gameBoard)</span>
<span class="n">outFile</span><span class="o" style="color: #666666;">.</span><span class="n">writelines</span><span class="p">(</span><span class="s" style="color: #4070a0;">'Starting Board</span><span class="se" style="color: #4070a0; font-weight: bold;">\n</span><span class="s" style="color: #4070a0;">'</span><span class="p">)</span>
<span class="n">printBoard</span> <span class="p">(</span><span class="n">gameBoard</span><span class="p">)</span>
<span class="n">listPossibleMoves</span><span class="p">(</span><span class="n">gameBoard</span><span class="p">,</span><span class="n">solutionCount</span><span class="p">)</span>
<span class="n">outFile</span><span class="o" style="color: #666666;">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">endTime</span> <span class="o" style="color: #666666;">=</span> <span class="n">datetime</span><span class="o" style="color: #666666;">.</span><span class="n">datetime</span><span class="o" style="color: #666666;">.</span><span class="n">now</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="p">(</span><span class="s" style="color: #4070a0;">'Starttime = '</span><span class="p">,</span> <span class="n">startTime</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="p">(</span><span class="s" style="color: #4070a0;">'EndTime = '</span><span class="p">,</span> <span class="n">endTime</span><span class="p">)</span></pre>
<br />
The first thing I do is allow the use of Python 3 print functions within Python 2. Something I have started to do more and more as I begin to think about making the transition from Python 2 to 3.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: #007020; font-weight: bold;">from</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">__future__</span> <span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="n">print_function</span> <span class="c" style="color: #60a0b0; font-style: italic;">#Allows python3 use of print()</span></pre>
<br />
I also use the copy libraries, and the datetime libraries in my program so these are imported here.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">copy</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">datetime</span></pre>
<br />
If you recall the layout of a Pin Solitaire board, it's a 7 x 7 square with the 4 pins in each of the corners missing.<br />
<br />
I have placed some Global Constants near the top of the program for a couple of reasons.<br />
<br />
<ul>
<li>It may be nice in the future to increase or decrease the size of the board. Who knows. Having the ability to make the modifications in one location in my program, which would affect the whole program, could be handy.</li>
<li>When I want to use the Height or Width of the board in my program, using Height or Width makes the program so much more readable when I return to it in a few months time. Seeing the number 7 crop up in the code somewhere doesn’t mean much, and can be quite confusing. This will definitely make my code easier to read.</li>
</ul>
<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #60a0b0; font-style: italic;">##Global Constants</span>
<span class="n">WIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">7</span>
<span class="n">HEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">7</span>
<span class="n">CORNERSIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span></pre>
<br />
I always use capital letters with my constants.<br />
<br />
The next are some variables which we will need to modify throughout the program.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #60a0b0; font-style: italic;">##Global Variables</span>
<span class="n">gameBoard</span> <span class="o" style="color: #666666;">=</span> <span class="p">{}</span>
<span class="n">storeBoards</span> <span class="o" style="color: #666666;">=</span> <span class="p">[]</span>
<span class="n">solutionCount</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span></pre>
<br />
Here is a quick explanation of each of these:<br />
<br />
gameBoard = {} - I am going to store my board in a dictionary. This allows me to store the co-ordinates of each hole on the board alongside the information explaining if there is a peg or not at that location.<br />
<br />
storeBoards = [] - I want to keep track of the moves I have made en route to a solution. This means that when I find a solution I have a list of all the moves I made to get there. If I reach a dead end, I will delete the move that took me there. This list of all the moves to reach a solution I will store in a list called storeBoards. <br />
<br />
solutionCount = 0 - I want to keep track of the number of moves I have made in total. This will be updated every time I drill deeper into a solution. The only real purpose in keeping track of the number of moves I have made, is to allow me to check that progress is being made. <br />
<br />
Now we get to the functions. These will make more sense if I explain them when we call them, rather than explain them all now.<br />
<br />
So with that in mind, lets jump down to the main section of the program, after all the functions.<br />
<br />
I want to log the time when I started solving the puzzle and when I finish. This will allow me to work out how long the puzzle took to solve.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">startTime</span> <span class="o" style="color: #666666;">=</span> <span class="n">datetime</span><span class="o" style="color: #666666;">.</span><span class="n">datetime</span><span class="o" style="color: #666666;">.</span><span class="n">now</span><span class="p">()</span></pre>
<br />
So I store the current date and time in a variable called startTime. I will print that later, with endTime, when we have solved the puzzle.<br />
<br />
I also want to save my solutions to a file. It's great showing the result on the screen, but once the puzzle is solved, I don’t want to have to keep running the solution again. So I will save the information in a text file called result.txt. This line creates and opens that file, so it is ready for data to be written to it.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">outFile</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">open</span> <span class="p">(</span><span class="s" style="color: #4070a0;">'result.txt'</span><span class="p">,</span><span class="s" style="color: #4070a0;">'w'</span><span class="p">)</span> </pre>
<br />
Now onto the fun bit. I want to populate the blank dictionary I created earlier with a populated game of pin solitaire.<br />
<br />
First of all let's populate it with a full version of solitaire. This means all holes are filled apart from the central one. The game most people recognise, and think of when they see pin solitaire.<br />
<br />
I will call a function to populate the board, so I have<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">gameBoard</span> <span class="o" style="color: #666666;">=</span> <span class="n">setupSolitaire</span><span class="p">(</span><span class="n">gameBoard</span><span class="p">)</span></pre>
<br />
This is calling the function setupSolitaire(), and passing the empty dictionary, gameBoard, into it. gameBoard will be update from whatever is returned from this function.<br />
<br />
Right lets leap into that function and see how that was written.<br />
<br />
Directly under the Global Variables, you will see where I have written the function.<br />
<br />
It starts off by defining the function and explains we are expecting a variable called board passed into it. Notice it doesn’t matter we are passing gameBoard into the function, but are referring to it as board within the function.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #60a0b0; font-style: italic;">#Setup Fully Populated Board</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">setupSolitaire</span><span class="p">(</span><span class="n">board</span><span class="p">):</span></pre>
<br />
Now we have already said we will refer to each of the holes on the board as co-ordinates on a grid. Top left being 0,0 bottom right being 6,6.<br />
<br />
This diagram explains what the co-ordinate system looks like.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEju0zdXY5VVFJoat3-Zt9R-1vCkNI7EOozlOyPVVH93vHjdtrrTBum74fL0AE4vht_KekAD9z-0exVc0dJjM3A1kvf9xPhBqj0KrQ-EhbMpBZIIffvgqhJIC3G29uj381cICPYtVSIibY0/s1600/Sudoku_Layout.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEju0zdXY5VVFJoat3-Zt9R-1vCkNI7EOozlOyPVVH93vHjdtrrTBum74fL0AE4vht_KekAD9z-0exVc0dJjM3A1kvf9xPhBqj0KrQ-EhbMpBZIIffvgqhJIC3G29uj381cICPYtVSIibY0/s320/Sudoku_Layout.png" width="312" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
We start by saying<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">y</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span> <span class="p">(</span><span class="n">HEIGHT</span><span class="p">):</span></pre>
<br />
This iterates through all the numbers from 0 to HEIGHT. We know HEIGHT is 7 so we will see the numbers 0,1,2,3,4,5,6. There is no number 7, but if you count them you will see there are 7 numbers.<br />
<br />
We then iterate through all the numbers in the range WIDTH<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span> <span class="p">(</span><span class="n">WIDTH</span><span class="p">):</span></pre>
<br />
This is a fairly common procedure of iterating through items such as co-ordinates.<br />
<br />
Now we want to populate all positions on our board with a peg. Except the four pegs in each corner, oh and the central hole!<br />
<br />
For a standard game we know that if the X co-ordinate falls in the first or last two columns AND the Y co-ordinates fall in the top or bottom two rows, then we will know that these should be blank, and not part of the game. This is what the next line states.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="p">((</span><span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="n">CORNERSIZE</span><span class="p">)</span> <span class="ow" style="color: #007020; font-weight: bold;">or</span> <span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="n">WIDTH</span><span class="o" style="color: #666666;">-</span><span class="n">CORNERSIZE</span><span class="p">,</span><span class="n">WIDTH</span><span class="p">))</span>
<span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="p">(</span><span class="n">y</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="n">CORNERSIZE</span><span class="p">)</span> <span class="ow" style="color: #007020; font-weight: bold;">or</span> <span class="n">y</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="n">HEIGHT</span><span class="o" style="color: #666666;">-</span><span class="n">CORNERSIZE</span><span class="p">,</span><span class="n">HEIGHT</span><span class="p">))):</span></pre>
<br />
These lines use the constants we have declared at the start of our program. Using WIDTH, HEIGHT and CORNERSIZE to determine which co-ordinates should and should not be part of the board.<br />
<br />
If they should not be part of the game, we make that co-ordinate in the dictionary associate with a space, ' '.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">board</span><span class="p">[</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">' '</span></pre>
<br />
If it's not a corner piece, we then look for the middle piece, which we want to make a O, to indicate there is no peg in the hole.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">x</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">WIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">2</span><span class="p">)</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">y</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">HEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">2</span><span class="p">):</span>
<span class="n">board</span><span class="p">[</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span></pre>
<br />
Else, for all other positions, we assign an X, to indicate there is a peg in the hole. <br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">board</span><span class="p">[</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'X'</span></pre>
<br />
Finally we want to pass the updated board back from our function, which we do so using<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">board</span></pre>
<br />
<br />
While researching the game a little more for the blog, I realised that there are many options for start games. While I am sure most people play the full version of pin solitaire, for test purposes, as will become clear later, its good to have some easier versions to solve.<br />
<br />
So there are 6 alternative games you can run. These are currently commented out. However if you wanted to run one of these games then, you would comment out<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">gameBoard</span> <span class="o" style="color: #666666;">=</span> <span class="n">setupSolitaire</span><span class="p">(</span><span class="n">gameBoard</span><span class="p">)</span></pre>
<br />
And uncomment the game you want to solve.<br />
<br />
To comment out a line, add a # in front of it, and delete the # if you want to uncomment a line. <br />
<br />
So for each of the next six games, you need to create a function to set up the board as you like.<br />
<br />
Once you know how to create one of these the others all follow the same pattern. Therefore I will explain just one to you, and let you read the code to see how the others work. Lets use the Cross as the example.<br />
<br />
So the next line of code you see is<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">gameBoard</span> <span class="o" style="color: #666666;">=</span> <span class="n">setupCross</span><span class="p">(</span><span class="n">gameBoard</span><span class="p">)</span></pre>
<br />
Which sends gameBoard to the function setupCross(), in much the same way as when we called the setupSolitaire() function.<br />
<br />
We will write this function now.<br />
<br />
Underneath the setupSolitaire() function you wrote earlier, create the function with<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">setupCross</span><span class="p">(</span><span class="n">board</span><span class="p">):</span></pre>
<br />
There are a number of ways to create the layout you need but the one I opted for was to call the setupSolitaire() function to fully populate the board, and then remove the pegs we no longer want. Lets call the function setupSolitaire() first of all.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">board</span> <span class="o" style="color: #666666;">=</span> <span class="n">setupSolitaire</span><span class="p">(</span><span class="n">board</span><span class="p">)</span></pre>
<br />
You know by now this line populates the board fully, which we have just created.<br />
<br />
The cross layout needs to look as follows<br />
<br />
OOO <br />
OXO <br />
OOXXXOO<br />
OOOXOOO<br />
OOOXOOO<br />
OOO <br />
OOO <br />
<br />
To do this we simply pick all the co-ordinates that need to change from being a X to a O.<br />
<br />
To change the top left peg, we use the co-ordinate [2,0].<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span></pre>
<br />
Where the 2 represents the X co-ordinate and the 0 the Y co-ordinate.<br />
<br />
We know from earlier our co-ordinate system starts with [0,0] in the top left corner. Therefore in X, the first two co-ordinates are a space , ‘ ‘,. These need to stay the same so we don’t modify them.<br />
<br />
We are simply changing items in our dictionary, from an 'X' to a 'O' for each co-ordinate that needs to change.<br />
<br />
We have to go through all the other co-ordinates which require changing. This will look as follows:<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span>
<span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span></pre>
<br />
The last change is actually putting a peg in the central position.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">board</span><span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'X'</span></pre>
<br />
Finally we return our modified board.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">board</span></pre>
<br />
We now have to go through a similar process for all the other starting shapes we need. We need to have a line of code to call the different starting positions, and a function to create each of them.<br />
<br />
The different starting layouts are:<br />
<br />
a plus<br />
<br />
OOO <br />
OXO <br />
OOOXOOO<br />
OXXXXXO<br />
OOOXOOO<br />
OXO <br />
OOO <br />
<br />
a fireplace<br />
<br />
XXX <br />
XXX <br />
OOXXXOO<br />
OOXOXOO<br />
OOOOOOO<br />
OOO <br />
OOO <br />
<br />
a pyramid<br />
<br />
OOO <br />
OXO <br />
OOXXXOO<br />
OXXXXXO<br />
XXXXXXX<br />
OOO<br />
OOO<br />
<br />
an arrow<br />
<br />
OXO <br />
XXX <br />
OXXXXXO<br />
OOOXOOO<br />
OOOXOOO<br />
XXX <br />
XXX<br />
<br />
<br />
and finally a diamond.<br />
<br />
OXO <br />
XXX <br />
OXXXXXO<br />
XXXXXXX<br />
OXXXXXO<br />
XXX <br />
OXO <br />
<br />
<br />
As I have shown you all the patters I don’t think I need to explain each of these to you in great detail!<br />
<br />
Now we want to start to write the results to the text file we have created. Before we jump straight in and start writing the files, we should try to organise the file we create, otherwise it will not make sense when we open it at a later date.<br />
<br />
First, we should show the board in the initial starting position. This will help us identify which problem we are solving. Let's write a line of text to the file, which explains what we are storing. <br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">outFile</span><span class="o" style="color: #666666;">.</span><span class="n">writelines</span><span class="p">(</span><span class="s" style="color: #4070a0;">'Starting Board</span><span class="se" style="color: #4070a0; font-weight: bold;">\n</span><span class="s" style="color: #4070a0;">'</span><span class="p">)</span></pre>
<br />
This line will write “Starting Board” to the file (outFile) we created earlier.<br />
<br />
The \n part explains we want a new line in the file after Starting Board.<br />
<br />
Now we call a function called printBoard, to print the board. If we simply printed the dictionary holding gameBoard we would get the whole contents of the dictionary, including the co-ordinates, and not the nice little print out of the board we are after.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">printBoard</span> <span class="p">(</span><span class="n">gameBoard</span><span class="p">)</span></pre>
<br />
Now go back to the top of your program and underneath all the functions to create the different start locations, you want to create the printBoard function.<br />
<br />
First name the function and declare you are passing your board into the function.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">printBoard</span><span class="p">(</span><span class="n">board</span><span class="p">):</span></pre>
<br />
If we were to simply print the gameboard, we would be printing the dictionary, and it would not look like a solitaire board.<br />
<br />
If you remember from earlier we created a text file which we want to save the results to. Well that saving will happen in this function. I will also include the code to print the result to the screen at this point. My code has the code which prints to the screen commented out, so it is ignored by the program. However if I wanted to print the code to the screen, these lines can be un-commented to allow me to do so.<br />
<br />
First we have to iterate through all the items in our dictionary.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">y</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span> <span class="p">(</span><span class="n">HEIGHT</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span> <span class="p">(</span><span class="n">WIDTH</span><span class="p">):</span></pre>
<br />
We have already seen how we do this earlier in the program, when we were creating the standard layout of the board.<br />
<br />
Now to print each item you would have the code.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #60a0b0; font-style: italic;">#print (board[x,y], end = " ") #The end prevents new lines being printed </span></pre>
<br />
This line prints what is stored in the dictionary for the co-ordinate [x,y]. I have added 'end = " "', as this stops a new line being printed after each item. Try with and without it later if you want to see the difference it makes. As I mentioned earlier I have commented out the code to print to the screen, but you can change this by uncommenting this line.<br />
<br />
Now we want to write what is stored at the location [x,y] to our text file.<br />
<br />
When we originally opened our text file we stored it as a variable outFile. This means if we want to do anything to our text file, we can do it to outFile.<br />
<br />
The code to write to the file is as follows<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">outFile</span><span class="o" style="color: #666666;">.</span><span class="n">writelines</span><span class="p">(</span><span class="n">board</span><span class="p">[</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">])</span> </pre>
<br />
The . after outFile shows we are treating outFile as an object. The syntax when working with an object is object.action.<br />
<br />
So the object is outFile, and the action we want to do to this is writelines(). We want to write what is held in the dictionary at location [x,y] to the file. This is the same as what we wanted to print. Simply board[x,y].<br />
<br />
Now once we have exhausted the end of all the items in the first row, we want to print the next row on a new line. To do this, at the same indentation level as the for y in range line, we add the following.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #60a0b0; font-style: italic;">#print ('\n')</span>
<span class="n">outFile</span><span class="o" style="color: #666666;">.</span><span class="n">writelines</span><span class="p">(</span><span class="s" style="color: #4070a0;">'</span><span class="se" style="color: #4070a0; font-weight: bold;">\n</span><span class="s" style="color: #4070a0;">'</span><span class="p">)</span> </pre>
<br />
The print line, prints a new line. \n is the method used to indicate a new line. Again this is commented out, as I don't want to use it just now, but being able to uncomment the line if I want to print to the screen gives me the option to do that.<br />
<br />
We also write a new line to outFile in much the same way.<br />
<br />
Now when we have been through all the items, both in x and y, we will want to do the same thing.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #60a0b0; font-style: italic;">#print ('\n')</span>
<span class="n">outFile</span><span class="o" style="color: #666666;">.</span><span class="n">writelines</span><span class="p">(</span><span class="s" style="color: #4070a0;">'</span><span class="se" style="color: #4070a0; font-weight: bold;">\n</span><span class="s" style="color: #4070a0;">'</span><span class="p">)</span></pre>
<br />
Finally we return the function. I have stated we are returning None. You could just use return, but it makes it clearer I intended to return nothing from the function.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
Now we have a function to print the board, lets go back to our main part of the function.<br />
<br />
We see we are now calling a new function called listPossibleMoves, and passing our board into this, and the variable solutionCount which will store a count we will need as our program progresses.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">listPossibleMoves</span><span class="p">(</span><span class="n">gameBoard</span><span class="p">,</span><span class="n">solutionCount</span><span class="p">)</span></pre>
<br />
This is the most crucial function in our program, which does the majority of the work.<br />
<br />
Before we dive straight in let us think about this function.<br />
<br />
We have already decided we will use Depth-first search. This uses something called a recursive function. A fancy name for saying a function which can call itself. It's quite easy to create a recursive function which keeps calling itself, over and over and over again. It would do this for ever. Therefore we have to structure our function properly, to stop this happening.<br />
<br />
I am going to structure my function as follows:<br />
<br />
If a solution has been found<br />
<span style="white-space: pre;"> </span>return<br />
else check all possible moves<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if a move is possible make the move<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>Call the function again with the board layout which reflects the move<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>undo the move<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
That's a very brief overview of what we want our function to do. I have added in a few extra things in my code, to make it suit my needs a little more, but you will see those as we go along. <br />
<br />
Before we dive into writing this function, I have separated the check to see if a solution has been found into a separate function. It is perhaps best to explain that function now, rather than in the middle of writing our listPossibleMoves() function.<br />
<br />
So directly after our printBoard() function we will name our checkResult() function, and state we are passing into it a board, which is obvious, as we will need to supply it something to check.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">checkResult</span><span class="p">(</span><span class="n">board</span><span class="p">):</span></pre>
<br />
So how do we know if the puzzle has been solved? Well... there would only be one peg left. So we can simply count the pegs. If there is more than one, then we have not succeeded, if there is one, the puzzle is solved. Pretty simple huh?The first thing we do is create something to keep track of our counting.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">count</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span></pre>
<br />
Now we check every item in the board.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">board</span><span class="p">:</span></pre>
<br />
If there is an X at that location we can increase the count.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">board</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="s" style="color: #4070a0;">'X'</span><span class="p">:</span>
<span class="n">count</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span> </pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span> <br />
To save time if the count gets above 1 we know we have not yet solved the puzzle, so we can return False<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">count</span> <span class="o" style="color: #666666;">></span><span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">False</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span> <br />
Otherwise, the count must be 1, it can never be less than 1, as there will always be one peg on the board. So we return True<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span><span class="c" style="color: #60a0b0; font-style: italic;"># The count must be 1</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">True</span></pre>
<br />
So we can pass a board into this function, and if it is solved, it will return True, else it will return false.<br />
<br />
Right so after that brief distraction, lets get back into writing the listPossibleMoves() function. Directly under our checkResult() function, we will declare listPossibleMoves. <br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">listPossibleMoves</span><span class="p">(</span><span class="n">gameBoard</span><span class="p">,</span><span class="n">solutionCount</span><span class="p">):</span></pre>
<br />
So this line names our function as listPossibleMoves, and shows we are passing in the current version of our gameBoard into it, as well as the variable which is called solutionCount.<br />
<br />
We now want to check if a solution has been found. Let's do this using the function we have just written called checkResult.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">checkResult</span><span class="p">(</span><span class="n">gameBoard</span><span class="p">)</span> <span class="o" style="color: #666666;">==</span> <span class="bp" style="color: #007020;">True</span><span class="p">:</span></pre>
<br />
We know that checkResult returning True means we have solved the puzzle. <br />
<br />
In our overview of this function, we said the next thing we would do is return. However before we do that, lets do a few other things.<br />
<br />
We should write the solution to the file we have created. To make our file a little easier to read, we should write a text line that explains this is the start of a solution.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">outFile</span><span class="o" style="color: #666666;">.</span><span class="n">writelines</span><span class="p">(</span><span class="s" style="color: #4070a0;">'Start Solution</span><span class="se" style="color: #4070a0; font-weight: bold;">\n\n</span><span class="s" style="color: #4070a0;">'</span><span class="p">)</span></pre>
<br />
Remember \n creates a new line therefore \n\n creates two new lines.<br />
<br />
Now we iterate through the list which is storing all the moves we have made so far. For each one, we will print that item, using our printBoard() function we wrote earlier. This will save the item passed into it to a file, and if we have uncommented the print statements, then it will also print the results to the screen.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">storeBoards</span><span class="p">:</span>
<span class="n">printBoard</span><span class="p">(</span><span class="n">item</span><span class="p">)</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
Once all the moves to the solution have been made, we will write another line, which says we are at the end of the solution.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">outFile</span><span class="o" style="color: #666666;">.</span><span class="n">writelines</span><span class="p">(</span><span class="s" style="color: #4070a0;">'End Solution</span><span class="se" style="color: #4070a0; font-weight: bold;">\n\n</span><span class="s" style="color: #4070a0;">'</span><span class="p">)</span></pre>
<br />
Finally we return from the function, as we said we would. We are returning solutionCount to ensure we keep this value up to date.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">solutionCount</span></pre>
<br />
When planning this function out we said we would next check all possible moves. As the first part of the function was an 'if' statement, this part needs to be an 'else' statement.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span> </pre>
<br />
So how do we check all possible moves? Well, we know that the pegs can only jump one of four ways. They can go up, down, left or right.<br />
<br />
We know that we only want to attempt to move a peg, and not a hole.<br />
<br />
We also know that a peg can only move if it jumps over another peg, into a hole.<br />
<br />
Anything else? Well there is one other thing. If we are near the edge of the playing area, then we don't want to start looking beyond the playing area, as this will throw up an error. So we should bear this in mind.<br />
<br />
Let us first of all check each of the positions on the board.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">gameBoard</span><span class="p">:</span></pre>
<br />
We want to now check each of the ways a peg at that position, if it is indeed a peg, can move. We will have to do these one at a time.<br />
<br />
Lets start with the peg moving to the right. The next line looks quite complicated.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;"><</span> <span class="p">(</span><span class="n">WIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="mi" style="color: #40a070;">2</span><span class="p">)</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'X'</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'O'</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'X'</span><span class="p">:</span></pre>
<br />
but it really isn't. We will break it own into smaller sections. <br />
<br />
We mentioned earlier that we want to make sure that a move to the right stays within the bounds of the board we have created. We should only check pegs that are not within the nearest two columns of the right hand side. The right hand side is equal to our variable WIDTH, so we want to check pegs that are in a column less than WIDTH - 2.<br />
<br />
Some of you may be asking should that not be less than WIDTH - 1? Well lets look at this is more detail.<br />
<br />
If WIDTH = 7, this means we have 7 pegs. However these have an x co-ordinates of either a 0,1,2,3,4,5 or a 6.<br />
<br />
WIDTH - 2 = 7 - 2 = 5.<br />
<br />
Less than 5 are co-ordinates 0,1,2,3 or a 4.<br />
<br />
As co-ordinate 4 is the 5th peg along, that can still make a jump to the right. If we used WIDTH - 1, that would leave us with co-ordinate 5, the 6th peg along. We would be checking if there is a peg two to the right of this, we would need a peg in co-ordinate 7, or the 8th peg along, which doesn't exist.<br />
<br />
Hopefully that made sense!<br />
<br />
We know that each item is defined by a co-ordinate system [x,y]. If we want to examine the x aspect of that we need to look in position 0 in the list. We can isolate this by saying item[0].<br />
<br />
Therefore the first thing we want to check is<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;"><</span> <span class="p">(</span><span class="n">WIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="mi" style="color: #40a070;">2</span><span class="p">)</span></pre>
<br />
We also said we wanted to check if the item we are looking at is a peg. This would be an 'X'.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'X'</span></pre>
<br />
Now if we are moving a peg to the right, we need to check the spot two places to the right is a O, indicating a space.<br />
<br />
To do that, lets check what is in that space.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'O'</span></pre>
<br />
By simply increasing the x co-ordinate of the item by 2 we can check if a O is in the position two places to the right.<br />
<br />
Whats the last thing we need to check? That the item 1 place to our right is an X, as we have to jump over a peg.<br />
<br />
<span class="n" style="font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.01em; line-height: 15.6px;">gameBoard</span><span class="p" style="font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.01em; line-height: 15.6px;">[</span><span class="n" style="font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.01em; line-height: 15.6px;">item</span><span class="p" style="font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.01em; line-height: 15.6px;">[</span><span class="mi" style="color: #40a070; font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.01em; line-height: 15.6px;">0</span><span class="p" style="font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.01em; line-height: 15.6px;">]</span><span class="o" style="color: #666666; font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.01em; line-height: 15.6px;">+</span><span class="mi" style="color: #40a070; font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.01em; line-height: 15.6px;">1</span><span class="p" style="font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.01em; line-height: 15.6px;">,</span><span class="n" style="font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.01em; line-height: 15.6px;">item</span><span class="p" style="font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.01em; line-height: 15.6px;">[</span><span class="mi" style="color: #40a070; font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.01em; line-height: 15.6px;">1</span><span class="p" style="font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.01em; line-height: 15.6px;">]]</span><span class="o" style="color: #666666; font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.01em; line-height: 15.6px;">==</span><span class="s" style="color: #4070a0; font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.01em; line-height: 15.6px;">'X'</span><br />
<br />
We can put all these individual elements together in one line, and using 'and' state they all need to be true.<br />
<br />
<div class="hlcode" style="background-color: white;">
<div class="syntax" style="clear: both;">
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;"><</span> <span class="p">(</span><span class="n">WIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="mi" style="color: #40a070;">2</span><span class="p">)</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'X'</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'O'</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'X'</span><span class="p">:</span>
</pre>
<div>
<span class="p" style="font-family: 'PT Sans', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif; font-size: 14px;"><br /></span>
<br />
<div class="p1">
<span class="s1">So what do we have to do if all these things are true? Well we need to make the move. That entails jumping the peg two places to the right, and removing the peg we have jumped over.</span></div>
<div class="p1">
<span class="s1"><br /></span></div>
Easy. Or maybe not. We need to copy the game-board first of all, so then we can always come back to the board if the path we take to solve the puzzle doesn't work out. We have to do a deepcopy, otherwise when the copy of the board changes, the original will change also.</div>
</div>
</div>
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">new</span> <span class="o" style="color: #666666;">=</span> <span class="n">copy</span><span class="o" style="color: #666666;">.</span><span class="n">deepcopy</span><span class="p">(</span><span class="n">gameBoard</span><span class="p">)</span></pre>
<br />
So how do we change our board to match the fact that a peg has jumped over another peg.<br />
<br />
Well the first thing is that the location where the peg was becomes empty.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">new</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'O'</span></pre>
<br />
Remember we are modifying our new copy of the board, and not the original board, as we will want to come back to that.<br />
<br />
The next thing is the space we have jumped the peg into becomes a peg and not a space.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">new</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]]</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">'X'</span></pre>
<br />
Finally the peg we have jumped over should be removed from the board.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">new</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]]</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">'O'</span></pre>
<br />
Perfect.<br />
<br />
As we have made a move, lets increase the count keeping track of the number of tries we have had at solving the puzzle.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">solutionCount</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span></pre>
<br />
When solving the puzzle, it is nice to ensure something is actually happening. Therefore every million (yes really) times we make a move, we should print something, so you know that the program has not crashed, and is still working.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="p">(</span><span class="n">solutionCount</span> <span class="o" style="color: #666666;">%</span> <span class="mi" style="color: #40a070;">1000000</span><span class="p">)</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">0</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="p">(</span><span class="n">solutionCount</span><span class="p">,</span><span class="s" style="color: #4070a0;">'solutionCount'</span><span class="p">)</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
solutionCount % 1000000 checks to see if there are any remainders when you divide solutionCount by 1000000. If there are no remainders, we know it is exactly divisible by 1000000, so we shall print the number. It's more for our sanity to check the program is running rather than aiding our program.<br />
<br />
Now we do a check to see if we have already been to the new position. This is to stop us getting into a loop of returning to the same position again and again. However this is not necessary in our program, as there is no way to return to a previous state in Pin Solitaire as you are removing pins each move. However it would be necessary for solving other puzzles, such as the Rubiks cube, where you can return to a previous state. Therefore I have kept it in, as a reminder.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">new</span> <span class="ow" style="color: #007020; font-weight: bold;">not</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">storeBoards</span><span class="p">:</span></pre>
<br />
We now want to add the new position to our list which is keeping track of all the moves we have made. This will mean we have an up to date list of all the moves to reach a solution.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">storeBoards</span><span class="o" style="color: #666666;">.</span><span class="n">append</span><span class="p">(</span><span class="n">new</span><span class="p">)</span></pre>
<br />
The next line is the most crucial line in Depth First Search. Have a read and see if you can notice what it does.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">solutionCount</span> <span class="o" style="color: #666666;">=</span> <span class="n">listPossibleMoves</span><span class="p">(</span><span class="n">new</span><span class="p">,</span><span class="n">solutionCount</span><span class="p">)</span></pre>
<br />
It calls the function we are already in, but with the Pin Solitaire board reflecting the move we have just made, and the solutionCount updated. The function is calling itself. This is known as a recursive function. We have made a move, and now we start drilling deeper into that move.<br />
<br />
Imagine if we start to analyse the move we have just made, and realise there are no possible moves? We we will return from the function we have just jumped into, and we will want to check the other possible moves. Such as if the pin we are analysing tried to jump left or up or down, instead of right.<br />
<br />
We will also want to remove the new position from the storeBoards, as that is no longer part of the solution we are analysing. Lets do that now.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">storeBoards</span><span class="o" style="color: #666666;">.</span><span class="n">remove</span><span class="p">(</span><span class="n">new</span><span class="p">)</span></pre>
<br />
As we have now returned to this function, after delving deeper into a solution we want to analyse what happens if we had jumped left or up or down instead.<br />
<br />
Lets now examine the code below the comment<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #60a0b0; font-style: italic;">##Check if piece can move in - X</span></pre>
<br />
Well the code for jumping left is very similar to jumping right. However there are a few small differences. Instead of making sure we are two places from the right of the board, we need to be two places from the left. We also need to be looking to the left and not to the right, to see if the move is possible. Therefore the first line changes to look like<br />
<br />
<div class="hlcode" style="background-color: white; font-family: "PT Sans", "Lucida Grande", "Lucida Sans Unicode", Geneva, Verdana, sans-serif; font-size: 14px;">
<div class="syntax" style="clear: both;">
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">></span> <span class="p">(</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'X'</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'O'</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'X'</span><span class="p">:</span>
</pre>
<div>
<span class="p"><br /></span></div>
</div>
</div>
If we decide to make the move, we need to modify the pins to the left of the pin we are looking at.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">new</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]]</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">'X'</span>
<span class="n">new</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]]</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">'O'</span></pre>
<br />
Everything else is the same!<br />
<br />
So now we have checked the possibility of jumping right and left, we need to look to see what happens if we jump down.<br />
<br />
Examine the code below.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #60a0b0; font-style: italic;">##Check if piece can move in + Y</span></pre>
<br />
In a similar way to ensuring we did not jump off the board when we jumped right, we need to do the same thing for down. Therefore we need to look at the Y co-ordinate and not the X co-ordinate, and check we are less than HEIGHT (not WIDTH) - 2<br />
<br />
i.e. item[1] < (HEIGHT - 2)<br />
<br />
<div class="hlcode" style="background-color: white; font-family: "PT Sans", "Lucida Grande", "Lucida Sans Unicode", Geneva, Verdana, sans-serif; font-size: 14px;">
<div class="syntax" style="clear: both;">
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;"><</span> <span class="p">(</span><span class="n">HEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="mi" style="color: #40a070;">2</span><span class="p">)</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'X'</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">],</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'O'</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">gameBoard</span><span class="p">[</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">],</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'X'</span><span class="p">:</span>
</pre>
<div>
<span class="p"><br /></span></div>
</div>
</div>
You will see that the X part of the co-ordinate is staying the same, but we are checking what the state of the board is in the positions if we were to move down, by looking what happens if we increase the Y part of the co-ordinate.<br />
<br />
When we decide to make the move, it is the Y co-ordinate we increase to modify the board to suit the move we have just made.<br />
<br />
It is now easy to see what changes we need to make in the code following the<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #60a0b0; font-style: italic;">##Check if piece can move in - Y</span></pre>
<br />
comment. I will let you look into those yourself.<br />
<br />
So what happens if we have been through all the moves, and none are possible. Well we saw earlier that if the puzzle had been solved, and there was only one pin left we should return solutionCount which will allow us to in effect undo the last move we have made.<br />
<br />
If we end up getting to a situation where there are no moves available, we should also return solutionCount and see what happened if we jumped the peg another direction.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">solutionCount</span></pre>
<br />
There are two return statements in this function. The one which is part of the 'if' statement would return us up a level if a solution has been found. This first return statement will only happen if a solution has been found, which means the function will have called itself several times, and there is only one peg left. This second return statement, in the else part of the statement, could be called for similar reasons i.e. if it has reached the end of a branch, but not found any solution. This would mean eventually, once all possibilities have been checked, the program would return to the main part of the program.<br />
<br />
If the program got this far it, and has exited all the recursive functions, then it would have finished its analysis of the board, and all possible moves. Any possible solutions will have been written to the result.txt file. Therefore we can now close the file.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">outFile</span><span class="o" style="color: #666666;">.</span><span class="n">close</span><span class="p">()</span></pre>
<br />
We will also now make a note of the time when the program ended.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">endTime</span> <span class="o" style="color: #666666;">=</span> <span class="n">datetime</span><span class="o" style="color: #666666;">.</span><span class="n">datetime</span><span class="o" style="color: #666666;">.</span><span class="n">now</span><span class="p">()</span></pre>
<br />
And finally, as we have stored both the start and the end times we can print them both, so help us determine the length of time the analysis took.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="p">(</span><span class="s" style="color: #4070a0;">'Starttime = '</span><span class="p">,</span> <span class="n">startTime</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="p">(</span><span class="s" style="color: #4070a0;">'EndTime = '</span><span class="p">,</span> <span class="n">endTime</span><span class="p">)</span></pre>
<br />
And that is the end of the program. All that is left to do is to run it. A word or warning though, if you are looking to solve the full puzzle, it really does take some time. So much so that I have not yet managed to leave a computer running long enough to prove a solution is found. I have however solved many of the other starting positions. The smaller ones take a matter of seconds to solve. So while it is quite a bit easier to solve than the Rubiks cube there is still a lot of processing to do on this.<br />
<br />
For those of you interested in this, have a look at these web pages, which explain more about solving pin solitaire.<br />
<br />
http://www.jaapsch.net/puzzles/solitaire.htm<br />
http://www.durangobill.com/Peg33.html<br />
http://home.comcast.net/~gibell/pegsolitaire/<br />
<br />
I hope that you have found this tutorial interesting, and that it has introduced you to the notion of Depth First Search. Let me know if you use it to solve any interesting puzzles!<br />
<br />
<br />
<br />
<br />Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com11tag:blogger.com,1999:blog-8250429656532783188.post-74355662668268991012015-04-03T15:33:00.000+01:002015-04-03T15:33:41.137+01:00Find Raspberry Pi IP Address using your Phone or TabletPreviously I have posted a very useful blog explaining how to <a href="http://trevorappleton.blogspot.co.uk/2013/03/remotely-find-raspberry-pi-ip-address.html" target="_blank">Remotely Find Raspberry Pi IP Address.</a> This used a tool called Nmap which works on Linux, Macs and Windows.<br />
<br />
Nmap is very powerful and is a great tool to use.<br />
<br />
Recently however I was introduced to a very simple to use app called Fing.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/jJxMM5TPcztJIMG8yUZLCcWbxocqoAi8ClMomQvfoOC9MNot1U6VQ846oIWJ4qkmnYs=w300-rw" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/jJxMM5TPcztJIMG8yUZLCcWbxocqoAi8ClMomQvfoOC9MNot1U6VQ846oIWJ4qkmnYs=w300-rw" height="200" width="200" /></a></div>
<br />
<br />
Fing is an app which is available for most smartphones and tablets. I run it off both Android and an iPad.<br />
<br />
Simply install it, and then load it up. It analyses your network and returns a list of all the IP Addresses and the Computers name associated with them. It really is that simple!<br />
<br />
Here is the entry for my Raspberry Pi, which clearly shows the IP address is 192.168.1.110.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiUPkSIQpEJ5SNj02F30ErNyrc44JsjPf8CqAqo2m-pFVX7BvdPKTiUESLdLAf_Qf31yOtneegf4LSydhoX9aQ_z3ViFOytBjItg5Swp-gAVe-IyW2fX_kOh79ma2ct2wE_miPYsJBPkQ/s1600/Fing_Analysis.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiUPkSIQpEJ5SNj02F30ErNyrc44JsjPf8CqAqo2m-pFVX7BvdPKTiUESLdLAf_Qf31yOtneegf4LSydhoX9aQ_z3ViFOytBjItg5Swp-gAVe-IyW2fX_kOh79ma2ct2wE_miPYsJBPkQ/s1600/Fing_Analysis.png" height="53" width="400" /></a></div>
<br />
Fing is such a simple and easy tool to use I am sure you will find it indispensable in no time!Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com1tag:blogger.com,1999:blog-8250429656532783188.post-50588579712274619292015-04-02T11:26:00.000+01:002015-04-02T11:26:02.453+01:00Refactoring Pong using Object-Oriented PythonSince writing my blog post explaining how to <a href="http://trevorappleton.blogspot.co.uk/2014/04/writing-pong-using-python-and-pygame.html" target="_blank">Write Pong Using Python and Pygame</a> the guys over at <a href="https://www.webucator.com/" target="_blank">Webucator</a> (a <a href="https://www.webucator.com/programming/python.cfm" target="_blank">Python Training Company</a>) have refactored it to include OOP. They have created an excellent video tutorial on this as part of their new free self-paced "Python Solutions from the Web" course they are developing.<br />
<br />
You should definitely check out the video as they really have done an awesome job!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/3FoUs-mRnvE/0.jpg" frameborder="0" height="266" src="http://www.youtube.com/embed/3FoUs-mRnvE?feature=player_embedded" width="320"></iframe></div>
<br />
Nat who helped create the tutorial was also kind enough to provide the source code which I have included below, which will help you follow the video.<br />
<br />
Enjoy!<br />
<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">pygame</span><span class="o" style="color: #666666;">,</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">sys</span>
<span class="kn" style="color: #007020; font-weight: bold;">from</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">pygame.locals</span> <span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># Set up the colours</span>
<span class="n">BLACK</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">)</span>
<span class="n">WHITE</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">)</span>
<span class="n">window_width</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">400</span>
<span class="n">window_height</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">300</span>
<span class="n">display_surf</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_mode</span><span class="p">((</span><span class="n">window_width</span><span class="p">,</span><span class="n">window_height</span><span class="p">))</span>
<span class="n">fps_clock</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">time</span><span class="o" style="color: #666666;">.</span><span class="n">Clock</span><span class="p">()</span>
<span class="n">fps</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">40</span> <span class="c" style="color: #60a0b0; font-style: italic;"># Number of frames per second</span>
<span class="k" style="color: #007020; font-weight: bold;">class</span> <span class="nc" style="color: #0e84b5; font-weight: bold;">Game</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">__init__</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">,</span><span class="n">line_thickness</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">10</span><span class="p">,</span><span class="n">speed</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">5</span><span class="p">):</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">line_thickness</span> <span class="o" style="color: #666666;">=</span> <span class="n">line_thickness</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">speed</span> <span class="o" style="color: #666666;">=</span> <span class="n">speed</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">score</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Initiate variable and set starting positions</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#any future changes made within rectangles</span>
<span class="n">ball_x</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">int</span><span class="p">(</span><span class="n">window_width</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">2</span> <span class="o" style="color: #666666;">-</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">line_thickness</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">2</span><span class="p">)</span>
<span class="n">ball_y</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">int</span><span class="p">(</span><span class="n">window_height</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">2</span> <span class="o" style="color: #666666;">-</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">line_thickness</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">2</span><span class="p">)</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">Ball</span><span class="p">(</span><span class="n">ball_x</span><span class="p">,</span><span class="n">ball_y</span><span class="p">,</span><span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">line_thickness</span><span class="p">,</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">line_thickness</span><span class="p">,</span><span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">speed</span><span class="p">)</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">paddles</span> <span class="o" style="color: #666666;">=</span> <span class="p">{}</span>
<span class="n">paddle_height</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">50</span>
<span class="n">paddle_width</span> <span class="o" style="color: #666666;">=</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">line_thickness</span>
<span class="n">user_paddle_x</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">20</span>
<span class="n">computer_paddle_x</span> <span class="o" style="color: #666666;">=</span> <span class="n">window_width</span> <span class="o" style="color: #666666;">-</span> <span class="n">paddle_width</span> <span class="o" style="color: #666666;">-</span> <span class="mi" style="color: #40a070;">20</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">paddles</span><span class="p">[</span><span class="s" style="color: #4070a0;">'user'</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">Paddle</span><span class="p">(</span><span class="n">user_paddle_x</span><span class="p">,</span>
<span class="n">paddle_width</span><span class="p">,</span> <span class="n">paddle_height</span><span class="p">)</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">paddles</span><span class="p">[</span><span class="s" style="color: #4070a0;">'computer'</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">AutoPaddle</span><span class="p">(</span><span class="n">computer_paddle_x</span><span class="p">,</span>
<span class="n">paddle_width</span><span class="p">,</span> <span class="n">paddle_height</span><span class="p">,</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">ball</span><span class="p">,</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">speed</span><span class="p">)</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">scoreboard</span> <span class="o" style="color: #666666;">=</span> <span class="n">Scoreboard</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Draws the arena the game will be played in. </span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">draw_arena</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">):</span>
<span class="n">display_surf</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">((</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">))</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Draw outline of arena</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">display_surf</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span>
<span class="p">((</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">),(</span><span class="n">window_width</span><span class="p">,</span><span class="n">window_height</span><span class="p">)),</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">line_thickness</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #40a070;">2</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Draw centre line</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">display_surf</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span>
<span class="p">(</span><span class="nb" style="color: #007020;">int</span><span class="p">(</span><span class="n">window_width</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">2</span><span class="p">),</span><span class="mi" style="color: #40a070;">0</span><span class="p">),</span>
<span class="p">(</span><span class="nb" style="color: #007020;">int</span><span class="p">(</span><span class="n">window_width</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">2</span><span class="p">),</span><span class="n">window_height</span><span class="p">),</span>
<span class="nb" style="color: #007020;">int</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">line_thickness</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">4</span><span class="p">))</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">update</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">):</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">move</span><span class="p">()</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">paddles</span><span class="p">[</span><span class="s" style="color: #4070a0;">'computer'</span><span class="p">]</span><span class="o" style="color: #666666;">.</span><span class="n">move</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">hit_paddle</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">paddles</span><span class="p">[</span><span class="s" style="color: #4070a0;">'computer'</span><span class="p">]):</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bounce</span><span class="p">(</span><span class="s" style="color: #4070a0;">'x'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">hit_paddle</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">paddles</span><span class="p">[</span><span class="s" style="color: #4070a0;">'user'</span><span class="p">]):</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bounce</span><span class="p">(</span><span class="s" style="color: #4070a0;">'x'</span><span class="p">)</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">score</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">pass_computer</span><span class="p">():</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">score</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">5</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">pass_player</span><span class="p">():</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">score</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">draw_arena</span><span class="p">()</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="p">()</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">paddles</span><span class="p">[</span><span class="s" style="color: #4070a0;">'user'</span><span class="p">]</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="p">()</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">paddles</span><span class="p">[</span><span class="s" style="color: #4070a0;">'computer'</span><span class="p">]</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="p">()</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">scoreboard</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">score</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">class</span> <span class="nc" style="color: #0e84b5; font-weight: bold;">Paddle</span><span class="p">(</span><span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">sprite</span><span class="o" style="color: #666666;">.</span><span class="n">Sprite</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">__init__</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">,</span><span class="n">x</span><span class="p">,</span><span class="n">w</span><span class="p">,</span><span class="n">h</span><span class="p">):</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">x</span> <span class="o" style="color: #666666;">=</span> <span class="n">x</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">w</span> <span class="o" style="color: #666666;">=</span> <span class="n">w</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">h</span> <span class="o" style="color: #666666;">=</span> <span class="n">h</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">int</span><span class="p">(</span><span class="n">window_height</span> <span class="o" style="color: #666666;">/</span> <span class="mi" style="color: #40a070;">2</span> <span class="o" style="color: #666666;">-</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">h</span> <span class="o" style="color: #666666;">/</span> <span class="mi" style="color: #40a070;">2</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Creates Rectangle for paddle.</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">x</span><span class="p">,</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">y</span><span class="p">,</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">w</span><span class="p">,</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">h</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Draws the paddle</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">draw</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">):</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Stops paddle moving too low</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">window_height</span> <span class="o" style="color: #666666;">-</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">w</span><span class="p">:</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">=</span> <span class="n">window_height</span> <span class="o" style="color: #666666;">-</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">w</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Stops paddle moving too high</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">w</span><span class="p">:</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">=</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">w</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Draws paddle</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">display_surf</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Moves the paddle</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">move</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">,</span><span class="n">pos</span><span class="p">):</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">=</span> <span class="n">pos</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">class</span> <span class="nc" style="color: #0e84b5; font-weight: bold;">AutoPaddle</span><span class="p">(</span><span class="n">Paddle</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">__init__</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">,</span><span class="n">x</span><span class="p">,</span><span class="n">w</span><span class="p">,</span><span class="n">h</span><span class="p">,</span><span class="n">ball</span><span class="p">,</span><span class="n">speed</span><span class="p">):</span>
<span class="nb" style="color: #007020;">super</span><span class="p">()</span><span class="o" style="color: #666666;">.</span><span class="n">__init__</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">w</span><span class="p">,</span><span class="n">h</span><span class="p">)</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">ball</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">speed</span> <span class="o" style="color: #666666;">=</span> <span class="n">speed</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">move</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">):</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#If ball is moving away from paddle, center bat</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">dir_x</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;"><</span> <span class="nb" style="color: #007020;">int</span><span class="p">(</span><span class="n">window_height</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">2</span><span class="p">):</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">speed</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;">></span> <span class="nb" style="color: #007020;">int</span><span class="p">(</span><span class="n">window_height</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">2</span><span class="p">):</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">-=</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">speed</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#if ball moving towards bat, track its movement. </span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">dir_x</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;"><</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span><span class="p">:</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">speed</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">-=</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">speed</span>
<span class="k" style="color: #007020; font-weight: bold;">class</span> <span class="nc" style="color: #0e84b5; font-weight: bold;">Ball</span><span class="p">(</span><span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">sprite</span><span class="o" style="color: #666666;">.</span><span class="n">Sprite</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">__init__</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">,</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">,</span><span class="n">w</span><span class="p">,</span><span class="n">h</span><span class="p">,</span><span class="n">speed</span><span class="p">):</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">x</span> <span class="o" style="color: #666666;">=</span> <span class="n">x</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">=</span> <span class="n">y</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">w</span> <span class="o" style="color: #666666;">=</span> <span class="n">w</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">h</span> <span class="o" style="color: #666666;">=</span> <span class="n">h</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">speed</span> <span class="o" style="color: #666666;">=</span> <span class="n">speed</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">dir_x</span> <span class="o" style="color: #666666;">=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span> <span class="c" style="color: #60a0b0; font-style: italic;">## -1 = left 1 = right</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">dir_y</span> <span class="o" style="color: #666666;">=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span> <span class="c" style="color: #60a0b0; font-style: italic;">## -1 = up 1 = down</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">x</span><span class="p">,</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">y</span><span class="p">,</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">w</span><span class="p">,</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">h</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#draws the ball</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">draw</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">):</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">display_surf</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#moves the ball returns new position</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">move</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">):</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">x</span> <span class="o" style="color: #666666;">+=</span> <span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">dir_x</span> <span class="o" style="color: #666666;">*</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">speed</span><span class="p">)</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">dir_y</span> <span class="o" style="color: #666666;">*</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">speed</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Checks for a collision with a wall, and 'bounces' ball off it.</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">hit_ceiling</span><span class="p">()</span> <span class="ow" style="color: #007020; font-weight: bold;">or</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">hit_floor</span><span class="p">():</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">bounce</span><span class="p">(</span><span class="s" style="color: #4070a0;">'y'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">hit_wall</span><span class="p">():</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">bounce</span><span class="p">(</span><span class="s" style="color: #4070a0;">'x'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">bounce</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">,</span><span class="n">axis</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">axis</span> <span class="o" style="color: #666666;">==</span> <span class="s" style="color: #4070a0;">'x'</span><span class="p">:</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">dir_x</span> <span class="o" style="color: #666666;">*=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">axis</span> <span class="o" style="color: #666666;">==</span> <span class="s" style="color: #4070a0;">'y'</span><span class="p">:</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">dir_y</span> <span class="o" style="color: #666666;">*=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">hit_paddle</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">,</span><span class="n">paddle</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">sprite</span><span class="o" style="color: #666666;">.</span><span class="n">collide_rect</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">,</span><span class="n">paddle</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">True</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">False</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">hit_wall</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="p">((</span><span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">dir_x</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;"><=</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">w</span><span class="p">)</span> <span class="ow" style="color: #007020; font-weight: bold;">or</span>
<span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">dir_x</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">1</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">>=</span> <span class="n">window_width</span> <span class="o" style="color: #666666;">-</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">w</span><span class="p">)):</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">True</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">False</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">hit_ceiling</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">dir_y</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><=</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">w</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">True</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">False</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">hit_floor</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">dir_y</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">1</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">>=</span> <span class="n">window_height</span> <span class="o" style="color: #666666;">-</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">w</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">True</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">False</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">pass_player</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;"><=</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">w</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">True</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">False</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">pass_computer</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">>=</span> <span class="n">window_width</span> <span class="o" style="color: #666666;">-</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">w</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">True</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">False</span>
<span class="k" style="color: #007020; font-weight: bold;">class</span> <span class="nc" style="color: #0e84b5; font-weight: bold;">Scoreboard</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">__init__</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">,</span><span class="n">score</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="n">x</span><span class="o" style="color: #666666;">=</span><span class="n">window_width</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">150</span><span class="p">,</span><span class="n">y</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">25</span><span class="p">,</span><span class="n">font_size</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">20</span><span class="p">):</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">score</span> <span class="o" style="color: #666666;">=</span> <span class="n">score</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">x</span> <span class="o" style="color: #666666;">=</span> <span class="n">x</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">=</span> <span class="n">y</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">font</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">font</span><span class="o" style="color: #666666;">.</span><span class="n">Font</span><span class="p">(</span><span class="s" style="color: #4070a0;">'freesansbold.ttf'</span><span class="p">,</span> <span class="n">font_size</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Displays the current score on the screen</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">display</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="p">,</span><span class="n">score</span><span class="p">):</span>
<span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">score</span> <span class="o" style="color: #666666;">=</span> <span class="n">score</span>
<span class="n">result_surf</span> <span class="o" style="color: #666666;">=</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">font</span><span class="o" style="color: #666666;">.</span><span class="n">render</span><span class="p">(</span><span class="s" style="color: #4070a0;">'Score = </span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">'</span> <span class="o" style="color: #666666;">%</span><span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">score</span><span class="p">),</span> <span class="bp" style="color: #007020;">True</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">)</span>
<span class="n">rect</span> <span class="o" style="color: #666666;">=</span> <span class="n">result_surf</span><span class="o" style="color: #666666;">.</span><span class="n">get_rect</span><span class="p">()</span>
<span class="n">rect</span><span class="o" style="color: #666666;">.</span><span class="n">topleft</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">x</span><span class="p">,</span> <span class="bp" style="color: #007020;">self</span><span class="o" style="color: #666666;">.</span><span class="n">y</span><span class="p">)</span>
<span class="n">display_surf</span><span class="o" style="color: #666666;">.</span><span class="n">blit</span><span class="p">(</span><span class="n">result_surf</span><span class="p">,</span> <span class="n">rect</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Main function</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">main</span><span class="p">():</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">init</span><span class="p">()</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_caption</span><span class="p">(</span><span class="s" style="color: #4070a0;">'Pong'</span><span class="p">)</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">mouse</span><span class="o" style="color: #666666;">.</span><span class="n">set_visible</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;"># make cursor invisible</span>
<span class="n">game</span> <span class="o" style="color: #666666;">=</span> <span class="n">Game</span><span class="p">(</span><span class="n">speed</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">4</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">while</span> <span class="bp" style="color: #007020;">True</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;">#main game loop</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">event</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">QUIT</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">quit</span><span class="p">()</span>
<span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># mouse movement commands</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">MOUSEMOTION</span><span class="p">:</span>
<span class="n">game</span><span class="o" style="color: #666666;">.</span><span class="n">paddles</span><span class="p">[</span><span class="s" style="color: #4070a0;">'user'</span><span class="p">]</span><span class="o" style="color: #666666;">.</span><span class="n">move</span><span class="p">(</span><span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">pos</span><span class="p">)</span>
<span class="n">game</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span>
<span class="n">fps_clock</span><span class="o" style="color: #666666;">.</span><span class="n">tick</span><span class="p">(</span><span class="n">fps</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">__name__</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span></pre>
Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com1tag:blogger.com,1999:blog-8250429656532783188.post-7232052247919185532015-03-22T18:42:00.000+00:002015-03-22T21:07:48.901+00:00Change MediaWiki LogoOnce you have your MediaWiki up and running (<a href="http://trevorappleton.blogspot.co.uk/2013/04/installing-mediawiki-on-raspberry-pi.html" target="_blank">check out my blog post which explains how to do this,</a>) there are a few things you will want to do. One of the first is to replace the MediaWiki logo, with one of your own. The MediaWiki logo shown even suggests that you do this and drops a hint on how you go about this.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUvqXV6gJBASU5JN_0ciqA8matQmQbm4M-UoywiM7UUiEkNedUVAraVBYoOWl52I_zo_YnCeP3Qcvl52h_SGFkz-Pn7KG1Lmthh1C-YfwFTUIAn3czLH14omjZKnNR0XJAfMgD5-sErag/s1600/Origonal+MediaWiki+Logo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUvqXV6gJBASU5JN_0ciqA8matQmQbm4M-UoywiM7UUiEkNedUVAraVBYoOWl52I_zo_YnCeP3Qcvl52h_SGFkz-Pn7KG1Lmthh1C-YfwFTUIAn3czLH14omjZKnNR0XJAfMgD5-sErag/s1600/Origonal+MediaWiki+Logo.png" height="125" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
The first thing you need to do it to copy your new logo to the correct place. The logo you want to display should be copied to the location:<br />
<br />
<div style="text-align: center;">
/var/lib/mediawiki/skins/common/images/</div>
<br />
The logo should be 135 x 135 pixels in size, otherwise you will not see all of it. If it's not square just make sure that the largest number of pixels in x or y is 135. I tend to use .png of .jpg images. Others may work, but I have not tested them!<br />
<br />
Once this in place you now have to change your settings file to point to the new logo.<br />
<br />
To change the logo it suggests you 'Set $wgLogo to the URL path to your own logo image.'<br />
<br />
Most modifications you make within MediaWiki are within the LocalSettings.php file. You will find this in the /var/lib/mediawiki/ folder. That may sound more complex than it is, but don't worry, it really is simple!<br />
<br />
To change this file, in the terminal, you need to type<br />
<br />
<pre style="background: rgb(0, 0, 0); border-radius: 2px; border: 1px solid rgb(204, 204, 204); color: #cccccc; font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="go" style="color: #888888;">sudo nano /var/lib/mediawiki/LocalSettings.php</span></pre>
<br />
For those that don't know.<br />
<ul>
<li>sudo - gives you administrator rights to change the file.</li>
<li>nano - is a text editor. There are others you can use but for demonstration purposes I am using nano. </li>
<li>/var/lib/mediawiki/LocalSettings.php - this is the location and name of the file you want to change. The file is LocalSettings.php, which is in location /var/lib/mediawiki/</li>
</ul>
<br />
This will open the LocalSettings.php file for you to edit.<br />
<br />
You should see something like this.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="cp" style="color: #007020;"><?php</span>
<span class="c1" style="color: #60a0b0; font-style: italic;"># This file was automatically generated by the MediaWiki 1.19.20+dfsg-0+deb7u3</span>
<span class="c1" style="color: #60a0b0; font-style: italic;"># installer. If you make manual changes, please keep track in case you</span>
<span class="c1" style="color: #60a0b0; font-style: italic;"># need to recreate them later.</span>
<span class="c1" style="color: #60a0b0; font-style: italic;">#</span>
<span class="c1" style="color: #60a0b0; font-style: italic;"># See includes/DefaultSettings.php for all configurable settings</span>
<span class="c1" style="color: #60a0b0; font-style: italic;"># and their default values, but don't forget to make changes in _this_</span>
<span class="c1" style="color: #60a0b0; font-style: italic;"># file, not there.</span>
<span class="c1" style="color: #60a0b0; font-style: italic;">#</span>
<span class="c1" style="color: #60a0b0; font-style: italic;"># Further documentation for configuration settings may be found at:</span>
<span class="c1" style="color: #60a0b0; font-style: italic;"># http://www.mediawiki.org/wiki/Manual:Configuration_settings</span>
<span class="c1" style="color: #60a0b0; font-style: italic;"># Protect against web entry</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="p">(</span> <span class="o" style="color: #666666;">!</span><span class="nb" style="color: #007020;">defined</span><span class="p">(</span> <span class="s1" style="color: #4070a0;">'MEDIAWIKI'</span> <span class="p">)</span> <span class="p">)</span> <span class="p">{</span>
<span class="k" style="color: #007020; font-weight: bold;">exit</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1" style="color: #60a0b0; font-style: italic;">## Uncomment this to disable output compression</span></pre>
<br />
Scroll down to the very bottom of this file using the arrow keys, and you should see the following two lines.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="x"># End of automatically generated settings.</span>
<span class="x"># Add more configuration options below.</span></pre>
<br />
This is where you should put your customised option. So below these two lines type in the following.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="x">$wgStylePath = " $wgScriptPath/skins";</span>
<span class="x">$wgLogo = "$wgStylePath/common/images/newLogo.jpg";</span></pre>
<br />
You should change newLogo.jpg to the name of your logo.<br />
<br />
Now press ctrl-x to exit. You will be asked if you want to 'Save modified buffer', Simply press y and then press return. This should exit from nano having saved your file.<br />
<br />
Now when you go to the main screen of your MediaWiki page you will see your new logo.<br />
<br />
I have simply used the header block from my blogpage, as you can see below.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5z-vEHoQAjDZHho4QwTXN1A-5_9gpg6bLDxZYwDD0XHOITxfeYI-tA4I1r0ADHsJ8mPARD2rNiaBIw-Zom2barSOpoV9bzM219Akmn0J8ilRQdWaBGQcEPewWLzH7B3ZSUB42ZlQDa2w/s1600/New+MediaWiki+Logo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5z-vEHoQAjDZHho4QwTXN1A-5_9gpg6bLDxZYwDD0XHOITxfeYI-tA4I1r0ADHsJ8mPARD2rNiaBIw-Zom2barSOpoV9bzM219Akmn0J8ilRQdWaBGQcEPewWLzH7B3ZSUB42ZlQDa2w/s1600/New+MediaWiki+Logo.png" height="105" width="400" /></a></div>
<br />
<br />
There you go, you have completed the first step to customising your MediaWiki page. A big improvement over the standard logo!<br />
<br />
<br />Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com4tag:blogger.com,1999:blog-8250429656532783188.post-292597798096506582015-03-03T12:59:00.000+00:002015-03-05T12:05:12.800+00:00Solving the Monty Hall Problem with Python. A while ago I stumbled across a problem which was referred to as the Monty Hall Problem. A problem which at first sight seems really simple.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://upload.wikimedia.org/wikipedia/commons/thumb/3/3f/Monty_open_door.svg/220px-Monty_open_door.svg.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://upload.wikimedia.org/wikipedia/commons/thumb/3/3f/Monty_open_door.svg/220px-Monty_open_door.svg.png" /></a></div>
<br />
<br />
It refers to a puzzle loosely based on the American television game show called 'Lets Make a Deal' hosted originally by Monty Hall.<br />
<br />
The host Monty Hall shows you three doors, and asks you to pick one.<br />
<br />
Behind one of these doors is the car of your dreams.<br />
Behind the other two is a goat.<br />
<br />
Now Monty hall asks you to pick a door, which you do.<br />
You will win whatever is behind that door.<br />
Happy with your choice?<br />
Now comes the difficult decision. Monty Hall asks would you like to change the door you have chosen?<br />
To help you, Monty Hall opens one of the other doors to reveal a goat. He never reveals the car.<br />
Do you swap doors?<br />
<br />
Surely you have now gone from a 1 in 3 chance of winning a Car, to a 1 in 2?<br />
Or have you?<br />
Does it matter if you swap?<br />
<br />
What do you all think?<br />
<br />
This problem became famous when a reader wrote in to Parade magazines ‘Ask Marilyn’ section in 1990. Marilyn Vos Savant answered the question correctly. However 10,000 people replied to her answer, the majority claiming she was wrong.<br />
<br />
Her claim is you should always swap, as you improve your chances of winning a car from 1/3 to 2/3.<br />
<br />
My statistics are not good enough to argue conclusively if Marilyn was right or not. However I decided to simulate the game in Python to prove once and for all if you should always swap doors!<br />
<br />
Let us first have a think about what our program needs to do.<br />
<ul>
<li>We need to set up a game with three doors. Each door needs either a goat or a car behind it. There should only be one car. </li>
<li>We then need to simulate Monty Hall revealing one of the other doors. To make our program simpler we will assume we are always opening door one. If the position of the goats and car are random then it doesn't matter which door we initially chose. </li>
<li>We need to be able to swap from our original choice when Monty Hall offers the swap.</li>
<li>We need to simulate many games where we do not swap our choice and check what the outcome is. </li>
<li>Then we need to do the same but we swap when offered by Monty Hall, and then check what the outcome is. </li>
<li>Finally we print the outcomes. </li>
</ul>
<br />
Here is my code to solve the problem. Have a read through it and see what you understand. Then I will break this down and explain it line by line.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #60a0b0; font-style: italic;">#Monty Hall Problem</span>
<span class="kn" style="color: #007020; font-weight: bold;">from</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">__future__</span> <span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="n">print_function</span> <span class="c" style="color: #60a0b0; font-style: italic;">#Allows python3 use of print()</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">random</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Variables used through out the program </span>
<span class="n">noSwap</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="n">swap</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="n">winCountNoSwap</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="n">loseCountNoSwap</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="n">winCountSwap</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="n">loseCountSwap</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="n">numberOfTests</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1000000</span> <span class="c" style="color: #60a0b0; font-style: italic;">#Alter this to change the number of simulations</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Function to set up the game. </span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Returns list with three items. 1 Car and 2 Goats randomly positioned. </span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">setUpGame</span><span class="p">():</span>
<span class="n">number</span> <span class="o" style="color: #666666;">=</span> <span class="n">random</span><span class="o" style="color: #666666;">.</span><span class="n">randint</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;">#random number 0,1 or 2</span>
<span class="n">blankDoors</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="c" style="color: #60a0b0; font-style: italic;">#sets up a new game</span>
<span class="n">count</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">blankDoors</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">count</span> <span class="o" style="color: #666666;">==</span> <span class="n">number</span><span class="p">:</span>
<span class="n">blankDoors</span><span class="p">[</span><span class="n">count</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'Car'</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">blankDoors</span><span class="p">[</span><span class="n">count</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'Goat'</span>
<span class="n">count</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">blankDoors</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Function to simulate Monty Hall revealing a goat. </span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Assumes contestant has door one.</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Reveals only a Goat in either door 2 or 3. </span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">reveal</span><span class="p">(</span><span class="n">currentGame</span><span class="p">):</span>
<span class="n">randomReveal</span> <span class="o" style="color: #666666;">=</span> <span class="n">random</span><span class="o" style="color: #666666;">.</span><span class="n">randint</span><span class="p">(</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">currentGame</span><span class="p">[</span><span class="n">randomReveal</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="s" style="color: #4070a0;">'Car'</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">randomReveal</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="n">randomReveal</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">randomReveal</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">currentGame</span><span class="p">[</span><span class="n">randomReveal</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'Reveal'</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">currentGame</span><span class="p">[</span><span class="n">randomReveal</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'Reveal'</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGame</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Simulates the player swapping doors. </span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Ensures they do not pick the 'Reveal' door. </span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">swapOption</span><span class="p">(</span><span class="n">currentGame</span><span class="p">):</span>
<span class="n">temp</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="s" style="color: #4070a0;">'Reveal'</span><span class="p">:</span>
<span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span>
<span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">temp</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span>
<span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">temp</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGame</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Runs through the game without swapping the door chosen.</span>
<span class="k" style="color: #007020; font-weight: bold;">while</span> <span class="n">noSwap</span> <span class="o" style="color: #666666;"><</span> <span class="n">numberOfTests</span><span class="p">:</span>
<span class="n">currentGame</span> <span class="o" style="color: #666666;">=</span> <span class="n">setUpGame</span><span class="p">()</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#print (currentGame)</span>
<span class="n">currentGame</span> <span class="o" style="color: #666666;">=</span> <span class="n">reveal</span><span class="p">(</span><span class="n">currentGame</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#print (currentGame)</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="s" style="color: #4070a0;">'Car'</span><span class="p">:</span>
<span class="n">winCountNoSwap</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">loseCountNoSwap</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">noSwap</span> <span class="o" style="color: #666666;">+=</span><span class="mi" style="color: #40a070;">1</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Runs through the game swapping the door chosen.</span>
<span class="k" style="color: #007020; font-weight: bold;">while</span> <span class="n">swap</span> <span class="o" style="color: #666666;"><</span> <span class="n">numberOfTests</span><span class="p">:</span>
<span class="n">currentGame</span> <span class="o" style="color: #666666;">=</span> <span class="n">setUpGame</span><span class="p">()</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#print (currentGame)</span>
<span class="n">currentGame</span> <span class="o" style="color: #666666;">=</span> <span class="n">reveal</span><span class="p">(</span><span class="n">currentGame</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#print (currentGame)</span>
<span class="n">currentGame</span> <span class="o" style="color: #666666;">=</span> <span class="n">swapOption</span><span class="p">(</span><span class="n">currentGame</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#print (currentGame)</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="s" style="color: #4070a0;">'Car'</span><span class="p">:</span>
<span class="n">winCountSwap</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">loseCountSwap</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">swap</span> <span class="o" style="color: #666666;">+=</span><span class="mi" style="color: #40a070;">1</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Calculates percentage of winning for each of the options and prints the result.</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="p">(</span><span class="s" style="color: #4070a0;">"Without swapping you win"</span> <span class="p">,</span><span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">winCountNoSwap</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span> <span class="p">(</span><span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">winCountNoSwap</span><span class="p">)</span> <span class="o" style="color: #666666;">+</span> <span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">loseCountNoSwap</span><span class="p">))</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #40a070;">100</span><span class="p">,</span> <span class="s" style="color: #4070a0;">"</span><span class="si" style="color: #70a0d0; font-style: italic;">% o</span><span class="s" style="color: #4070a0;">f the time."</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="p">(</span><span class="s" style="color: #4070a0;">"With swapping you win"</span> <span class="p">,</span><span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">winCountSwap</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span> <span class="p">(</span><span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">winCountSwap</span><span class="p">)</span> <span class="o" style="color: #666666;">+</span> <span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">loseCountSwap</span><span class="p">))</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #40a070;">100</span><span class="p">,</span> <span class="s" style="color: #4070a0;">"</span><span class="si" style="color: #70a0d0; font-style: italic;">% o</span><span class="s" style="color: #4070a0;">f the time."</span><span class="p">)</span>
</pre>
<br />
<br />
The first line is simply a comment to state what the program is doing. Anything preceded by a # is ignored by the program.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #60a0b0; font-style: italic;">#Monty Hall Problem</span></pre>
<br />
Next is a line I have started to use recently, as I think more about moving over to Python 3. This means I can use the same print functions in my program as used in Python 3.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: #007020; font-weight: bold;">from</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">__future__</span> <span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="n">print_function</span> <span class="c" style="color: #60a0b0; font-style: italic;">#Allows python3 use of print()</span></pre>
<br />
I will be calling some random numbers, so I need to import the random library.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">random</span></pre>
<br />
Now we create a few variables which we will use later in the program. At this stage we will just create them, and will discuss where they are used later in the blog.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #60a0b0; font-style: italic;">#Variables used through out the program </span>
<span class="n">noSwap</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="n">swap</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="n">winCountNoSwap</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="n">loseCountNoSwap</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="n">winCountSwap</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="n">loseCountSwap</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="n">numberOfTests</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1000000</span> <span class="c" style="color: #60a0b0; font-style: italic;">#Alter this to change the number of simulations</span></pre>
<br />
Now the first thing we said we would do was to set up a blank game, with three doors. Two doors should have a goat behind them, and one a car. These should be randomly selected.<br />
<br />
As setting up a blank game is something we will have to do before each of the simulations we run, I have put this code in a function to allow me to call it many times. The function in its entirety is here, afterwards we will run through it line by line.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #60a0b0; font-style: italic;">##Function to set up the game. </span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Returns list with three items. 1 Car and 2 Goats randomly positioned. </span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">setUpGame</span><span class="p">():</span>
<span class="n">number</span> <span class="o" style="color: #666666;">=</span> <span class="n">random</span><span class="o" style="color: #666666;">.</span><span class="n">randint</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;">#random number 0,1 or 2</span>
<span class="n">blankDoors</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="c" style="color: #60a0b0; font-style: italic;">#sets up a new game</span>
<span class="n">count</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">blankDoors</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">count</span> <span class="o" style="color: #666666;">==</span> <span class="n">number</span><span class="p">:</span>
<span class="n">blankDoors</span><span class="p">[</span><span class="n">count</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'Car'</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">blankDoors</span><span class="p">[</span><span class="n">count</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'Goat'</span>
<span class="n">count</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">blankDoors</span></pre>
<br />
The first line sets the function name, and as the brackets are empty explains we are not sending any variables into the function.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">setUpGame</span><span class="p">():</span></pre>
<br />
Now we know we want a car behind one door and a goat behind two. Therefore if we create a list holding the three things, one of these will be a car.<br />
<br />
Lets generate a number from 0 - 2 to decide which item in the list will be the car. You might be asking why not a number from 1-3, as there are three doors? Well lists in Python, along with most other languages, have the first item in position 0. So door 1 is at position 0 in the list. Therefore our random number needs to be a 0, 1 or a 2.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">number</span> <span class="o" style="color: #666666;">=</span> <span class="n">random</span><span class="o" style="color: #666666;">.</span><span class="n">randint</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;">#random number 0,1 or 2</span></pre>
<br />
Now we will create a list with three items in it, for now these are all set to 0.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">blankDoors</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="c" style="color: #60a0b0; font-style: italic;">#sets up a new game</span></pre>
<br />
We want to assign either goat or car to each of the items in the list. So, as we iterate through the list, lets keep count of where we are up to. If our count is equal to the random number we calculated, which covers only one of the locations in the list, then that should be the car, otherwise a goat should be assigned to the slot.<br />
<br />
So first make a count variable. As we iterate through the list this keeps track of the position in the list we are up to, either a 0, 1 or 2.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">count</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span> </pre>
<br />
<br />
This next line iterates through each of the items in the list one at a time.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">blankDoors</span><span class="p">:</span></pre>
<br />
<br />
We want to ensure if the count is equal to the random number we generated, this item in the list should be assigned as the car. First the check to see if the count is equal to the random number we generated earlier.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">count</span> <span class="o" style="color: #666666;">==</span> <span class="n">number</span><span class="p">:</span></pre>
<br />
<br />
If the count is equal to the number, then this position in the list should be turned into Car.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">blankDoors</span><span class="p">[</span><span class="n">count</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'Car'</span></pre>
<br />
<br />
If it isn't, then it should become a Goat.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">blankDoors</span><span class="p">[</span><span class="n">count</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'Goat'</span></pre>
<br />
<br />
Well we have now done everything we want to with that item in the list, so all that remains is we update the count ready to match the next items position in the list we are going to be looking at.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">count</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span></pre>
<br />
<br />
Notice to increase the count by one we use += 1. We could say count = count + 1, but as this is done often in Python there is a shortcut method of typing this as count += 1. If we wanted to remove 1 from count we could say count -= 1.<br />
<br />
Finally once we have finished iterating thorough the list, we want to return our now populated list back to the main program. We do this with<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">blankDoors</span></pre>
<br />
<br />
So now if we call this setUpGame() function, we will be returned a blank game. Perfect.<br />
<br />
The next thing on our list was to simulate Monty Hall revealing a goat in one of the doors the contestant has not chosen.<br />
<br />
For simplicity we are going to assume the contestant always chooses door 1. As the Goats and Cars are assigned randomly it really doesn't matter which door we say the contestant has chosen. This just makes our code easier for the simulations.<br />
<br />
As we will want Monty Hall to reveal a goat in all our games, I have written this part as a function, so we can easily call it as many times as we want.<br />
<br />
Here is the overall function, then we will break it down to see what it does.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #60a0b0; font-style: italic;">##Function to simulate Monty Hall revealing a goat. </span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Assumes contestant has door one.</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Reveals only a Goat in either door 2 or 3. </span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">reveal</span><span class="p">(</span><span class="n">currentGame</span><span class="p">):</span>
<span class="n">randomReveal</span> <span class="o" style="color: #666666;">=</span> <span class="n">random</span><span class="o" style="color: #666666;">.</span><span class="n">randint</span><span class="p">(</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">currentGame</span><span class="p">[</span><span class="n">randomReveal</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="s" style="color: #4070a0;">'Car'</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">randomReveal</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="n">randomReveal</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">randomReveal</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">currentGame</span><span class="p">[</span><span class="n">randomReveal</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'Reveal'</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">currentGame</span><span class="p">[</span><span class="n">randomReveal</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'Reveal'</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGame</span></pre>
<br />
<br />
First of all we set the name of the function. You can see we are passing the currentGame into it. This means the function has access to currentGame, and can make any modifications required.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">reveal</span><span class="p">(</span><span class="n">currentGame</span><span class="p">):</span></pre>
<br />
<br />
In the next line we create a random number which is either a 1 or a 2. We have stated that the contestant will always choose door 1, which is in position 0 in the list. We we want to ensure Monty Hall reveals either door 2 or 3, which are held in the list in position 1 or 2.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">randomReveal</span> <span class="o" style="color: #666666;">=</span> <span class="n">random</span><span class="o" style="color: #666666;">.</span><span class="n">randint</span><span class="p">(</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">)</span></pre>
<br />
We only want Monty Hall to reveal a goat. The next five lines look into if the random number matches a door which is hiding the car, which is a scenario we don't want. If this happens we get Monty Hall to switch the door he is about to reveal.<br />
<br />
First of all we look to see if the random number (stored in randomReveal) we have just created matches the location of the car.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">currentGame</span><span class="p">[</span><span class="n">randomReveal</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="s" style="color: #4070a0;">'Car'</span><span class="p">:</span></pre>
<br />
<br />
If it is a car behind the random door we want Monty Hall to reveal the other door. Therefore if he was going to reveal door 2 and this is a Car we want him to reveal door 3 which will be a goat and vice versa. The next few lines simply switch the randomReveal number to select the other position in the list. This is done by having if and else statements indented within the if statement above.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">randomReveal</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="n">randomReveal</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">randomReveal</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span></pre>
<br />
<br />
Notice that the else covers all other eventualities. In this case if randomReveal is not 1, it must be 2, in which case we want to set randomReveal to 1.<br />
<br />
Now so we know that door has been revealed let us change what is behind the door to say Reveal instead of Goat.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">currentGame</span><span class="p">[</span><span class="n">randomReveal</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'Reveal'</span></pre>
<br />
<br />
All that was to deal with the fact the Monty Hall was going to reveal a Car. If the randomReveal number was going to cause Monty Hall to reveal a goat, then thats ok. We will simply turn the goat behind that door into Reveal. Note that this else statement is at the same indentation level as the first if statement in the function. It is really important that you get the indentation right, as your whole program can change if it is wrong!<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">currentGame</span><span class="p">[</span><span class="n">randomReveal</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'Reveal'</span></pre>
<br />
<br />
Finally we return the modified version of current game which has one of the doors revealed.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGame</span></pre>
<br />
<br />
The next thing we said we had to do was to get the player to swap doors. Now this is not something which they player needs to do every-time, as we want to compare swapping with not swapping doors. But we do want our program to have the ability to simulate the player swapping doors when Monty Hall gives us the option.<br />
<br />
Again this is something we will need to do often in our simulation, so it is written in a function.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #60a0b0; font-style: italic;">##Simulates the player swapping doors. </span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Ensures they do not pick the 'Reveal' door. </span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">swapOption</span><span class="p">(</span><span class="n">currentGame</span><span class="p">):</span>
<span class="n">temp</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="s" style="color: #4070a0;">'Reveal'</span><span class="p">:</span>
<span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span>
<span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">temp</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span>
<span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">temp</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGame</span></pre>
<br />
The first line defines the function name and explains we are passing currentGame into the function.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">swapOption</span><span class="p">(</span><span class="n">currentGame</span><span class="p">):</span></pre>
<br />
<br />
The way we will do the swap may be a little different than you think. However it is to make our program a little easier. Rather than swap doors we have chosen, we will simply swap what is behind the doors. So the contestants door will still remain door 1, but we will swap what was behind door 1 with whatever is behind the door which Monty Hall has not revealed to us.<br />
<br />
The first thing we will do is to store what is behind the contestants door in a temporary variable called temp.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">temp</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span></pre>
<br />
<br />
We will use this to replace what is behind the door Monty Hall has not revealed in a minute or two.<br />
<br />
What we are trying to do is choose which door has not been revealed to be a goat by Monty Hall, and switch that one with the contestants door, which is door 1. We first check to see if door 2 (stored in position 1 in the list remember) is Reveal<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="s" style="color: #4070a0;">'Reveal'</span><span class="p">:</span></pre>
<br />
It is is, we want to swap what is behind door 3 (stored in the list in position 2) with what is behind the contestants door. This line takes what was behind door three and puts it in the position of the contestants door.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span></pre>
<br />
<br />
Now we need to take what was behind the contestants door and put this behind door 3. Hold on a second! We have just over written what was behind door 1. Luckily we made a copy by storing a copy in temp. So we simply copy what is in temp to the position in the list which is storing what is behind door 3.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">temp</span></pre>
<br />
<br />
We know Monty Hall has revealed either door 2 or door 3. Therefore if Door 2 is not 'Reveal' he must have revealed door 3. We use an else statement to deal with this scenario and then swap what is behind door 2 (position 1 in the list) with door 1 (position 0 in the list), using the same method as above.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span>
<span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">temp</span></pre>
<br />
<br />
Finally we return the values in currentGame which now reflect the player accepting the swap.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGame</span></pre>
<br />
<br />
Now we enter a while loop to run through a simulation of how many times you will win or lose if you do not swap doors when offered by Monty Hall.<br />
<br />
The first thing we do is start the while loop. We are going to need to use a few of those variables we created at the top of our program at this point. The whole of the while loop looks like this.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #60a0b0; font-style: italic;">##Runs through the game without swapping the door chosen.</span>
<span class="k" style="color: #007020; font-weight: bold;">while</span> <span class="n">noSwap</span> <span class="o" style="color: #666666;"><</span> <span class="n">numberOfTests</span><span class="p">:</span>
<span class="n">currentGame</span> <span class="o" style="color: #666666;">=</span> <span class="n">setUpGame</span><span class="p">()</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#print (currentGame)</span>
<span class="n">currentGame</span> <span class="o" style="color: #666666;">=</span> <span class="n">reveal</span><span class="p">(</span><span class="n">currentGame</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#print (currentGame)</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="s" style="color: #4070a0;">'Car'</span><span class="p">:</span>
<span class="n">winCountNoSwap</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">loseCountNoSwap</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">noSwap</span> <span class="o" style="color: #666666;">+=</span><span class="mi" style="color: #40a070;">1</span></pre>
<br />
<br />
The first line states that while noSwap is less than the numberOfTests the loop should keep going. This ensures that we run the tests as many times as stated in the numberOfTests variable. We could say while noSwap < 1000000: However in a few months time, it would be hard to remember what the 1000000 was used for. It is also harder to find it in the body of the program rather than at the top. We would also have to change it in a couple of locations.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: #007020; font-weight: bold;">while</span> <span class="n">noSwap</span> <span class="o" style="color: #666666;"><</span> <span class="n">numberOfTests</span><span class="p">:</span></pre>
<br />
<br />
The next thing we do is call our setUpGame function and store the result in currentGame.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">currentGame</span> <span class="o" style="color: #666666;">=</span> <span class="n">setUpGame</span><span class="p">()</span></pre>
<br />
<br />
There are some print statements in this while loop which I have commented out. I have left these in there to show you that when debugging I will often print the outputs out to ensure they are working as expected. However this slows the simulation, so I comment them out when running a real simulation.<br />
<br />
Monty Hall then wants to reveal a door which has a goat, and ask if you want to swap. We will have Monty Hall reveal the goat, but in this simulation you are not swapping.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">currentGame</span> <span class="o" style="color: #666666;">=</span> <span class="n">reveal</span><span class="p">(</span><span class="n">currentGame</span><span class="p">)</span></pre>
<br />
Now we start to check if the contestant has won. We know they will have won if what is behind their door is a car, unless of course they always wanted a goat! We have ensured that the contestants door is always door 1. And rather than swapping doors, we swapped what was behind the doors. As the item in position 0 in our list represents what is behind door 1 we can easily check if this is a car.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="s" style="color: #4070a0;">'Car'</span><span class="p">:</span></pre>
<br />
If it is the contestant has won! We will use another of those variables we created at the start to keep track of how many times the contestant has won<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">winCountNoSwap</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span></pre>
<br />
If they have not won then we keep track of the losses as well.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">loseCountNoSwap</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span></pre>
<br />
<br />
Finally we need to increase our count of how many simulations we have done otherwise our while loop will run forever.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">noSwap</span> <span class="o" style="color: #666666;">+=</span><span class="mi" style="color: #40a070;">1</span></pre>
<br />
Well that was the simulation for if we do not want to swap when offered by Monty Hall. We now do something similar for the option when we do want to swap when offered. Again we do this in a while loop.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #60a0b0; font-style: italic;">##Runs through the game swapping the door chosen.</span>
<span class="k" style="color: #007020; font-weight: bold;">while</span> <span class="n">swap</span> <span class="o" style="color: #666666;"><</span> <span class="n">numberOfTests</span><span class="p">:</span>
<span class="n">currentGame</span> <span class="o" style="color: #666666;">=</span> <span class="n">setUpGame</span><span class="p">()</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#print (currentGame)</span>
<span class="n">currentGame</span> <span class="o" style="color: #666666;">=</span> <span class="n">reveal</span><span class="p">(</span><span class="n">currentGame</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#print (currentGame)</span>
<span class="n">currentGame</span> <span class="o" style="color: #666666;">=</span> <span class="n">swapOption</span><span class="p">(</span><span class="n">currentGame</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#print (currentGame)</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">currentGame</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="s" style="color: #4070a0;">'Car'</span><span class="p">:</span>
<span class="n">winCountSwap</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">loseCountSwap</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">swap</span> <span class="o" style="color: #666666;">+=</span><span class="mi" style="color: #40a070;">1</span></pre>
<br />
This while loop is incredibly similar apart from two things.<br />
<br />
The variables have different names to reflect the fact that we are swapping. This means we don’t write over the information created in the previous while loop.<br />
<br />
We have an extra line in there to call the function which carries out the swap, to make the swap when offered. We wrote this function earlier. This line is.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">currentGame</span> <span class="o" style="color: #666666;">=</span> <span class="n">swapOption</span><span class="p">(</span><span class="n">currentGame</span><span class="p">)</span></pre>
<br />
Now we have all the data which we need to work out which is the better option, all we need to do it to calculate it and print it. We do that in the next two lines.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #60a0b0; font-style: italic;">##Calculates percentage of winning for each of the options and prints the result.</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="p">(</span><span class="s" style="color: #4070a0;">"Without swapping you win"</span> <span class="p">,</span><span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">winCountNoSwap</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span> <span class="p">(</span><span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">winCountNoSwap</span><span class="p">)</span> <span class="o" style="color: #666666;">+</span> <span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">loseCountNoSwap</span><span class="p">))</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #40a070;">100</span><span class="p">,</span> <span class="s" style="color: #4070a0;">"</span><span class="si" style="color: #70a0d0; font-style: italic;">% o</span><span class="s" style="color: #4070a0;">f the time."</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="p">(</span><span class="s" style="color: #4070a0;">"With swapping you win"</span> <span class="p">,</span><span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">winCountSwap</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span> <span class="p">(</span><span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">winCountSwap</span><span class="p">)</span> <span class="o" style="color: #666666;">+</span> <span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">loseCountSwap</span><span class="p">))</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #40a070;">100</span><span class="p">,</span> <span class="s" style="color: #4070a0;">"</span><span class="si" style="color: #70a0d0; font-style: italic;">% o</span><span class="s" style="color: #4070a0;">f the time."</span><span class="p">)</span></pre>
<br />
These lines print some text first of all, saying “Without/With swapping you win.”<br />
They then use the results we have gathered to calculate the percentage of winning.<br />
<br />
Using this equation<br />
<br />
<div style="text-align: center;">
<u> Wins </u> x 100%</div>
<div style="text-align: center;">
Wins + Losses </div>
<br />
(Wins + Losses) is used to add up the total of simulations done.<br />
<br />
But what is float for? Well in programming numbers can be stored as different things. All our numbers are stored as int which is short for integer. An integer is a whole number. However in Python if you do any maths on an int, the result will be an int also. Before we multiply our answer by 100 to get a percentage we will have a number less that 1, this will be rounded down to 0. Which is no good to use. To change our numbers to floating point, using float, ensures have decimal points. Carrying out maths on values which are floats will give us the answer as a float.<br />
<br />
The final part of each line is to finish off the text with ‘% of the time.’<br />
<br />
If you are interested in the results from this program, I can provide some below. I ran this program with the number of samples set to 1,000,000,000. Yes you read that correctly. I simulated 1 Billion game shows! Which really did not take long! The results are:<br />
<br />
<div style="text-align: center;">
Without swapping you win 33.3321941 % of the time.</div>
<div style="text-align: center;">
With swapping you win 66.6647868 % of the time.</div>
<br />
I hope you have enjoyed this blog post. What I learned from writing it is this is a fairly complex problem to think about, and it has fooled many people, including some top mathematicians. Although I would struggle to prove the answer from a mathematical point of view, this was a simple thing to solve in Python. <br />
<br />Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com0tag:blogger.com,1999:blog-8250429656532783188.post-12307297024844061862015-02-10T21:30:00.000+00:002015-03-03T16:31:13.406+00:00Check downloads using SHA-1 and MD5 When you download a large file, such as a distribution of Linux for the Raspberry Pi, you are provided with a checksum to check the download is all correct. Has anyone ever checked their download? Would you know how to? I have to admit I rarely check. However if things did go wrong it would be very easy to overlook the fact the download went wrong. As you will see in this blog it is also possible to use this tool to check that SD cards have been written to correctly.<br />
<br />
There are two types of checksum which are commonly used <a href="http://en.wikipedia.org/wiki/SHA-1" target="_blank">SHA-1</a> and <a href="http://en.wikipedia.org/wiki/MD5" target="_blank">MD5</a>. I will explain how to use both of these. <br />
<br />
First lets look how to do this on an Apple Mac.<br />
<br />
To determine the MD5 open the terminal and type either<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="go" style="color: #888888;">openssl md5 filename</span></pre>
<br />
or for SHA-1<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="go" style="color: #888888;">openssl sha1 filename</span></pre>
<br />
for the MD5 you don't need to type openssl.<br />
<br />
On a Linux system type the following into a terminal.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="go" style="color: #888888;">md5sum filename</span></pre>
<br />
and for SHA-1 you need to type<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="go" style="color: #888888;">sha1sum filename</span></pre>
<br />
depending which checksum you are wanting to use.<br />
<br />
Don't forget, if your filename is in a different folder, you will have to include the location along with the filename as below<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span style="color: #888888;">location/of/folder/filename</span></pre>
<br />
Did you know that you are able to check that the image has burned correctly onto say an SD Card by checking the card once you have burned it?<br />
<br />
For example on an Apple Mac to check a disk type the following<br />
<br />
<pre style="background: rgb(240, 240, 240); border-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="go" style="color: #888888;">sudo openssl sha1 /dev/rdisk2</span></pre>
<br />
where /dev/rdisk2 is the path to the disk you want to check. Note you will probably need to use the sudo command to ensure you have the correct permissions. This is handy if you want to check that all your disks have burned correctly.<br />
<br />
<br />Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com1tag:blogger.com,1999:blog-8250429656532783188.post-52081505821867741692014-11-01T13:40:00.000+00:002014-11-01T15:50:50.152+00:00Sending Email using PythonI often see people asking the question how do you send Email using Python?<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://cdn1.iconfinder.com/data/icons/simple-icons/4096/email-4096-black.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://cdn1.iconfinder.com/data/icons/simple-icons/4096/email-4096-black.png" width="200" /></a></div>
Well a few years ago I had the idea to write a program, which would automatically send an Email should a certain event happen. I have been meaning to include the Email code in a blog post, but have never managed to get around to it.<br />
<br />
Until now...<br />
<br />
So here is the code I used. I know it works with Gmail, but have not tested it with other providers, although I am sure a little modification would make it work.<br />
<br />
Remember this program requires you to store your Email password in plain text, something you need to be aware of!<br />
<br />
Just ensure you add your username and password where necessary, and change the other fields as required.<br />
<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #60a0b0; font-style: italic;">#!/usr/bin/python</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">smtplib</span>
<span class="n">SMTP_SERVER</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'smtp.gmail.com'</span>
<span class="n">SMTP_PORT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">587</span>
<span class="n">GMAIL_USERNAME</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'your_username@gmail.com'</span>
<span class="n">GMAIL_PASSWORD</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'your_gmail_password'</span> <span class="c" style="color: #60a0b0; font-style: italic;">#CAUTION: This is stored in plain text!</span>
<span class="n">recipient</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'recipient@email_address.com'</span>
<span class="n">subject</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'Email Subject'</span>
<span class="n">emailText</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'This is the content of the e-mail.'</span>
<span class="n">emailText</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">""</span> <span class="o" style="color: #666666;">+</span> <span class="n">emailText</span> <span class="o" style="color: #666666;">+</span> <span class="s" style="color: #4070a0;">""</span>
<span class="n">headers</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="s" style="color: #4070a0;">"From: "</span> <span class="o" style="color: #666666;">+</span> <span class="n">GMAIL_USERNAME</span><span class="p">,</span>
<span class="s" style="color: #4070a0;">"Subject: "</span> <span class="o" style="color: #666666;">+</span> <span class="n">subject</span><span class="p">,</span>
<span class="s" style="color: #4070a0;">"To: "</span> <span class="o" style="color: #666666;">+</span> <span class="n">recipient</span><span class="p">,</span>
<span class="s" style="color: #4070a0;">"MIME-Version: 1.0"</span><span class="p">,</span>
<span class="s" style="color: #4070a0;">"Content-Type: text/html"</span><span class="p">]</span>
<span class="n">headers</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">"</span><span class="se" style="color: #4070a0; font-weight: bold;">\r\n</span><span class="s" style="color: #4070a0;">"</span><span class="o" style="color: #666666;">.</span><span class="n">join</span><span class="p">(</span><span class="n">headers</span><span class="p">)</span>
<span class="n">session</span> <span class="o" style="color: #666666;">=</span> <span class="n">smtplib</span><span class="o" style="color: #666666;">.</span><span class="n">SMTP</span><span class="p">(</span><span class="n">SMTP_SERVER</span><span class="p">,</span> <span class="n">SMTP_PORT</span><span class="p">)</span>
<span class="n">session</span><span class="o" style="color: #666666;">.</span><span class="n">ehlo</span><span class="p">()</span>
<span class="n">session</span><span class="o" style="color: #666666;">.</span><span class="n">starttls</span><span class="p">()</span>
<span class="n">session</span><span class="o" style="color: #666666;">.</span><span class="n">ehlo</span>
<span class="n">session</span><span class="o" style="color: #666666;">.</span><span class="n">login</span><span class="p">(</span><span class="n">GMAIL_USERNAME</span><span class="p">,</span> <span class="n">GMAIL_PASSWORD</span><span class="p">)</span>
<span class="n">session</span><span class="o" style="color: #666666;">.</span><span class="n">sendmail</span><span class="p">(</span><span class="n">GMAIL_USERNAME</span><span class="p">,</span> <span class="n">recipient</span><span class="p">,</span> <span class="n">headers</span> <span class="o" style="color: #666666;">+</span> <span class="s" style="color: #4070a0;">"</span><span class="se" style="color: #4070a0; font-weight: bold;">\r\n\r\n</span><span class="s" style="color: #4070a0;">"</span> <span class="o" style="color: #666666;">+</span> <span class="n">emailText</span><span class="p">)</span>
<span class="n">session</span><span class="o" style="color: #666666;">.</span><span class="n">quit</span><span class="p">()</span></pre>
Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com2tag:blogger.com,1999:blog-8250429656532783188.post-11887001000123304062014-10-21T12:11:00.001+01:002016-01-19T20:45:02.544+00:00Infinite Monkey Theorem using PythonThey say that if you sat an infinite number of monkeys with an infinite number of typewriters, then they would write the complete works of Shakespeare. This is known as the <a href="http://en.wikipedia.org/wiki/Infinite_monkey_theorem">Infinite Monkey Theorem</a>. I always feel it would be nice to try the actual experiment out. I mean all these monkeys with typewriters would be kinda cool.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://upload.wikimedia.org/wikipedia/commons/f/f1/Monkey-typing.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://upload.wikimedia.org/wikipedia/commons/f/f1/Monkey-typing.jpg" height="223" width="400" /></a></div>
<br />
<br />
However wouldn't it be easier to get one monkey and one typewriter and give him an infinite amount of time to see how he goes?<br />
<br />
Although in theory it sounds simpler, getting hold of even a single monkey is not that easy.<br />
<br />
But what if we created a simulated monkey in Python? Now we are talking! That would be easy, and unlike a real monkey our simulated one could work all day and all night. No food required.<br />
<br />
Sounds like a plan for a blog post.<br />
<br />
However I want to give our virtual monkey a chance. If he managed to type the complete works of Shakespeare without worrying about punctuation, we would be happy right? Same goes for capital letters, let's just ignore them for now. We want to give him a fighting chance of completing his task.<br />
<br />
To help you get started I have taken a text file of the complete works of Shakespeare, and removed all punctuation and made all letters small. If any of you are thinking I did that by hand, think again. Python is your friend for automating tasks like that.<br />
<br />
Because the complete works is a large tome, I have also included a similar file, with just Hamlet. You can choose which one you want your monkey to attempt!<br />
<br />
As with all my blog posts I will give you the complete program first of all. Have a read through this and see how much of it you understand. Try and figure out those sections you don’t. I will then go through the program a line at a time explaining it in more detail.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">random</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">string</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">typeShakespeare</span><span class="p">(</span><span class="n">scriptRead</span><span class="p">):</span>
<span class="n">monkeyTyped</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">''</span>
<span class="k" style="color: #007020; font-weight: bold;">while</span> <span class="n">monkeyTyped</span> <span class="o" style="color: #666666;">==</span> <span class="s" style="color: #4070a0;">''</span> <span class="ow" style="color: #007020; font-weight: bold;">or</span> <span class="n">scriptRead</span><span class="o" style="color: #666666;">.</span><span class="n">count</span><span class="p">(</span><span class="n">monkeyTyped</span><span class="p">)</span> <span class="o" style="color: #666666;">>=</span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="n">monkeyTyped</span> <span class="o" style="color: #666666;">=</span> <span class="n">monkeyTyped</span> <span class="o" style="color: #666666;">+</span> <span class="p">(</span><span class="n">random</span><span class="o" style="color: #666666;">.</span><span class="n">choice</span><span class="p">(</span><span class="n">string</span><span class="o" style="color: #666666;">.</span><span class="n">ascii_lowercase</span> <span class="o" style="color: #666666;">+</span> <span class="s" style="color: #4070a0;">' '</span><span class="p">))</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="p">(</span><span class="n">monkeyTyped</span><span class="p">[:</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">])</span>
<span class="n">script</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">open</span><span class="p">(</span><span class="s" style="color: #4070a0;">'Shakespeare.txt'</span><span class="p">,</span><span class="s" style="color: #4070a0;">'r'</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;"># opens the files</span>
<span class="n">scriptRead</span> <span class="o" style="color: #666666;">=</span> <span class="n">script</span><span class="o" style="color: #666666;">.</span><span class="n">read</span><span class="p">()</span>
<span class="n">script</span><span class="o" style="color: #666666;">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">keyPresses</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="n">monkeyTyped</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">''</span>
<span class="k" style="color: #007020; font-weight: bold;">while</span> <span style="color: #007020;">len</span>(<span class="n">monkeyTyped)</span> <span class="o" style="color: #666666;">!=</span> <span class="nb" style="color: #007020;">len</span><span class="p">(</span><span class="n">scriptRead</span><span class="p">):</span> <span class="c" style="color: #60a0b0; font-style: italic;">## infinite loop ... unless the monkey does it!</span>
<span class="n">monkeyTyped</span> <span class="o" style="color: #666666;">=</span> <span class="n">typeShakespeare</span><span class="p">(</span><span class="n">scriptRead</span><span class="p">)</span>
<span class="n">keyPresses</span> <span class="o" style="color: #666666;">=</span> <span class="n">keyPresses</span> <span class="o" style="color: #666666;">+</span> <span class="nb" style="color: #007020;">len</span><span class="p">(</span><span class="n">monkeyTyped</span><span class="p">)</span> <span class="o" style="color: #666666;">+</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="nb" style="color: #007020;">len</span><span class="p">(</span><span class="n">monkeyTyped</span><span class="p">)</span> <span class="o" style="color: #666666;">>=</span><span class="mi" style="color: #40a070;">5</span><span class="p">:</span>
<span class="n">monkeyTyped</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">"'"</span><span class="o" style="color: #666666;">+</span><span class="n">monkeyTyped</span><span class="o" style="color: #666666;">+</span><span class="s" style="color: #4070a0;">"'"</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">monkeyTyped</span><span class="p">,</span> <span class="n">keyPresses</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">keyPresses</span><span class="o" style="color: #666666;">%</span><span class="mi" style="color: #40a070;">10000</span><span class="o" style="color: #666666;">==</span><span class="mi" style="color: #40a070;">0</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">keyPresses</span></pre>
<br />
The first thing we do is import a couple of libraries we will use. We want our monkey to type some random letters, so we will call on the random library. We will also be needing strings (many letters joined together) so we should import the string library as well.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">random</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">string</span></pre>
<br />
There is now a function called typeShakespeare(). It will make sense to explain this when we call it, so lets skip it for now.<br />
<br />
The aim of the program is to work out if the monkey has managed to type the complete works of Shakespeare, or Hamlet, if thats what you prefer. To do this we need to judge his effort against the finished script. Therefore we will open the file with the completed text.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">script</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">open</span><span class="p">(</span><span class="s" style="color: #4070a0;">'Shakespeare.txt'</span><span class="p">,</span><span class="s" style="color: #4070a0;">'r'</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;"># opens the files</span></pre>
<br />
Change this to read Hamlet.txt if you want to use Hamlet instead.<br />
<br />
We then store the text into a variable called scriptRead. To do this we use the .read() command on the script we have opened. Finally as we have the data stored in memory we will close the script.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">scriptRead</span> <span class="o" style="color: #666666;">=</span> <span class="n">script</span><span class="o" style="color: #666666;">.</span><span class="n">read</span><span class="p">()</span>
<span class="n">script</span><span class="o" style="color: #666666;">.</span><span class="n">close</span><span class="p">()</span></pre>
<br />
I have now created a variable called keyPresses and set this to 0. There are two reasons for this. When he has typed a word worth reporting I want to know how many key presses it took before he got there. I also want to keep an eye on my monkey, to make sure he is working. Therefore every time he has pressed a key a set number of times I will report back.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">keyPresses</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span></pre>
<br />
We also need to know what the monkey has typed and to keep an eye on that. Every-time he types a letter we will check he is on the right path. If he isn't, we will get him to start from scratch. We will create a blank string to store his effort in.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">monkeyTyped</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">''</span></pre>
<br />
Now we enter into our main loop which is a while loop.<br />
<br />
We want the monkey to keep typing until he has finished the job. If he hasn't then we will make him keep going. The first line of our while loop checks to see if what is stored in monkeyTyped is as long as the file we are looking into him typing. As we are checking the monkey is on the right track every letter, should he type something the length of the complete works of Shakespeare, then we will know he has achieved his goal.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: #007020; font-weight: bold;">while</span> <span style="color: #007020;">len</span>(<span class="n">monkeyTyped)</span> <span class="o" style="color: #666666;">!=</span> <span class="nb" style="color: #007020;">len</span><span class="p">(</span><span class="n">scriptRead</span><span class="p">):</span> <span class="c" style="color: #60a0b0; font-style: italic;">## infinite loop ... unless the monkey does it!</span></pre>
<div>
<span class="c" style="color: #60a0b0; font-style: italic;"><br /></span></div>
Now we call the function typeShakespeare we skipped over earlier and we store the result into monkeyTyped.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">monkeyTyped</span> <span class="o" style="color: #666666;">=</span> <span class="n">typeShakespeare</span><span class="p">(</span><span class="n">scriptRead</span><span class="p">)</span></pre>
<br />
I think it would be a good time to now go and write that function. It is in this function that the monkey does most of his work. He tries to type the complete works of Shakespeare. We will check his work every time he presses a key. If he is on the right track, we will let him continue. If what he has typed is not in Shakespeare, we will return his best efforts to our main program.<br />
<br />
So directly below import string we should type<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">typeShakespeare</span><span class="p">(</span><span class="n">scriptRead</span><span class="p">):</span></pre>
<br />
This defines our function and tells us we are passing scriptRead into it.<br />
<br />
As I mentioned we are going to be in this function while the monkey types something. The first thing we need to do is to set monkeyTyped to = ''<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">monkeyTyped</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">''</span></pre>
<br />
Now we enter a new while loop. This one needs to keep looping while the monkey has typed something which appears in Shakespeare.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">while</span> <span class="n">monkeyTyped</span> <span class="o" style="color: #666666;">==</span> <span class="s" style="color: #4070a0;">''</span> <span class="ow" style="color: #007020; font-weight: bold;">or</span> <span class="n">scriptRead</span><span class="o" style="color: #666666;">.</span><span class="n">count</span><span class="p">(</span><span class="n">monkeyTyped</span><span class="p">)</span> <span class="o" style="color: #666666;">>=</span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span></pre>
<br />
We do this by using scriptRead.count(monkeyTyped) >= 1 What does that even mean? Well we take the complete works of Shakespeare stored in scriptRead, and we do a count of how many times the thing in the brackets appears. If we put monkeyTyped into the brackets then it will count how many times monkeyCount appeared in scriptRead. We only need it to appear once but if it appears more than once, then that is ok as well. We check this with the greater than or equal to symbol >=.<br />
<br />
But the line also has monkeyTyped = ''. Why is that? Well when we start off this while loop the monkey has not typed anything, as we have set the variable to = '' , which means an empty string. This would mean our while loop would be false straight away, and our monkey would never start typing.<br />
<br />
To get around this we us an or condition. We check that monkeyTyped is '' or scriptRead.count(monkeyTyped) >= 1<br />
<br />
The next line is the line which does the actual typing.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">monkeyTyped</span> <span class="o" style="color: #666666;">=</span> <span class="n">monkeyTyped</span> <span class="o" style="color: #666666;">+</span> <span class="p">(</span><span class="n">random</span><span class="o" style="color: #666666;">.</span><span class="n">choice</span><span class="p">(</span><span class="n">string</span><span class="o" style="color: #666666;">.</span><span class="n">ascii_lowercase</span> <span class="o" style="color: #666666;">+</span> <span class="s" style="color: #4070a0;">' '</span><span class="p">))</span></pre>
<br />
We take monkeyTyped and we add the result of (random.choice(string.ascii_lowercase + ' ')) onto it and save the result as monkeyTyped.<br />
<br />
What on earth is (random.choice(string.ascii_lowercase + ' ')) ?<br />
<br />
Well we want to simulate the monkey typing on a keyboard. We have already said to make it easy we will not ask for punctuation, although we should ask him for a space between words. Thats not too much to ask is it? We also said we will not be too concerned about it being in capital letters.<br />
<br />
So random.choice picks something from inside the brackets by random selection. So what have we put in the brackets. The first thing is<br />
<br />
string.ascii_lowercase<br />
<br />
This creates a string of the lower case ascii letters. i.e<br />
<br />
abcdefghijklmnopqrstuvwxyz<br />
<br />
We also add onto the end of that a space using ' '<br />
<br />
Now remember this has a space between the two speech-marks. This is different from when we are creating a blank string, which doesn't have a space.<br />
<br />
Once he has typed a word, the loop will start again and check if what has been typed is in the complete works. If it is he will continue. If not he will go to the else statement.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="p">(</span><span class="n">monkeyTyped</span><span class="p">[:</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span></pre>
<br />
Here we return what he has typed. However remember we only get to this place if what is typed is not in the complete works. That's no use to us! We will need to remove the last letter of what he typed, as it was that last letter we know to have made perfect Shakespeare prose into gibberish.<br />
<br />
So we return monkeyTyped[:-1] which returns everything up to the last letter but not the last letter.<br />
<br />
Ok back to where we were in the main program.<br />
<br />
Remember we said we would keep track of the number of key presses? Well lets update that now. We know the monkey has just typed a word, so it is easy to determine the size of that word and increase keyPresses by that amount. Oh but the monkey typed a letter which turned his prose into gibberish. We should add that on as well as we want our count to be accurate!<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">keyPresses</span> <span class="o" style="color: #666666;">=</span> <span class="n">keyPresses</span> <span class="o" style="color: #666666;">+</span> <span class="nb" style="color: #007020;">len</span><span class="p">(</span><span class="n">monkeyTyped</span><span class="p">)</span> <span class="o" style="color: #666666;">+</span> <span class="mi" style="color: #40a070;">1</span></pre>
<br />
Whats the point of doing something if no one knows about it? Mmmmm... this blog post is perhaps not the best place to get into a philosophical debate. We want our monkey to report back if he has typed some Shakespeare. However we don't want him reporting back if he has just typed one letter do we? No one likes a show off!<br />
<br />
We only want to be informed if the length of what he has typed is greater than 5, although you can vary this depending on how much chat you want with your monkey.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="nb" style="color: #007020;">len</span><span class="p">(</span><span class="n">monkeyTyped</span><span class="p">)</span> <span class="o" style="color: #666666;">>=</span><span class="mi" style="color: #40a070;">5</span><span class="p">:</span></pre>
<br />
As we are reporting the monkeys best effort in that round of typing, and his efforts are going to be set back to the beginning, it doesn't matter if we play around with our monkeyTyped variable to help make his reporting a little nicer. Lets first of all add speech marks onto his typing, so we can see what he has typed.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">monkeyTyped</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">"'"</span><span class="o" style="color: #666666;">+</span><span class="n">monkeyTyped</span><span class="o" style="color: #666666;">+</span><span class="s" style="color: #4070a0;">"'"</span></pre>
<br />
Pay careful attention to those speech marks in there. Each side is a single quote ' surrounded by double quotes "<br />
<br />
Now we will print what the monkey has typed, and the number of keyPresses he has made in total so far.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">monkeyTyped</span><span class="p">,</span> <span class="n">keyPresses</span></pre>
<br />
Finally if you are only checking for big words the monkey may be away working some time before he gets to report back. I think its wise to check in on him every so often.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">keyPresses</span><span class="o" style="color: #666666;">%</span><span class="mi" style="color: #40a070;">10000</span><span class="o" style="color: #666666;">==</span><span class="mi" style="color: #40a070;">0</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">keyPresses</span></pre>
<br />
This line checks to see if the number of key presses he has made is a multiple of 10,000. The % checks if keyPresses / 10,000 has no remainder i.e. it is a multiple of 10,000. If it is then it will print the number of key-presses made. This only works if the key-presses are an exact multiple of 10,000. There will be times when the monkey is in the middle of a word when this happen, so it will not report back. However it reports enough to make you realise the monkey is still working and not fallen asleep.<br />
<br />
Remember to press F5 to save and run your program.<br />
<br />
That is the end of the program. All you need now it to download the complete works of Shakespeare or just Hamlet if thats what you want to use. Use the links below to do that.<br />
<br />
<a href="https://drive.google.com/file/d/0B87aGq7vEpoFUkVRUHJObVNyNGs/view?usp=sharing" target="_blank">Download complete works of Shakespeare</a><br />
<br />
<a href="https://drive.google.com/file/d/0B87aGq7vEpoFb08zeUNISmlrZEk/view?usp=sharing" target="_blank">Download Hamlet</a><br />
<br />
Well I hope you have enjoyed this simple program, and that it helped you learn a little bit of Python! Good luck to all your Monkeys typing away, let me know how they get on!<br />
<br />
I have created a version of this program which tweets the monkeys' progress. Check out the twitter feed <a href="https://twitter.com/TheMonkeyBard" target="_blank">@TheMonkeyBard</a>.Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com1tag:blogger.com,1999:blog-8250429656532783188.post-16277374329892233702014-08-28T14:07:00.002+01:002014-08-28T14:10:24.365+01:00Converting and Resizing Images Using PythonAs part of my wife's job a few years ago, she had to convert images from various file types to .jpg and then resize them to make them smaller. Sure this could be done in programs like GIMP or Photoshop, but it was a time consuming process. To speed things up I wrote her a Python program which would automatically convert and resize any images which were in the same folder as the Python program. It saved her a lot of time.<br />
<br />
Since then there have been a number of occasion when I have had to convert images to .jpg and then resize them, such as when I am using eBay. I always find this a cumbersome task, and often fall back on my Python program to do this for me.<br />
<br />
As I am sure this is something you will find useful I have made it the basis of my latest blog post.<br />
<br />
The program is quite simple, and does three things.<br />
<ol>
<li>Converts images to .jpg. </li>
<li>Deletes the original images. </li>
<li>Resizes images keeping the same aspect ratio.</li>
</ol>
<div>
Let us have a look at the whole program first and then we will go through it line by line.<br />
<br />
This is written in Python 2.7.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #60a0b0; font-style: italic;">## Required Modules</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">Image</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">glob</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">os</span>
<span class="c" style="color: #60a0b0; font-style: italic;">## Global Variables</span>
<span class="n">FILETYPES</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="s" style="color: #4070a0;">'*.tiff'</span><span class="p">,</span><span class="s" style="color: #4070a0;">'*.jpeg'</span><span class="p">,</span><span class="s" style="color: #4070a0;">'*.png'</span><span class="p">]</span>
<span class="n">NEWIMAGESIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">400</span>
<span class="c" style="color: #60a0b0; font-style: italic;">## Functions</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">convert2jpg</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">types</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">FILETYPES</span><span class="p">:</span>
<span class="n">openFiles</span> <span class="o" style="color: #666666;">=</span> <span class="n">glob</span><span class="o" style="color: #666666;">.</span><span class="n">glob</span><span class="p">(</span><span class="n">types</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">files</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">openFiles</span><span class="p">:</span>
<span class="n">inFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">Image</span><span class="o" style="color: #666666;">.</span><span class="n">open</span><span class="p">(</span><span class="n">files</span><span class="p">)</span>
<span class="n">fileName</span> <span class="o" style="color: #666666;">=</span> <span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">path</span><span class="o" style="color: #666666;">.</span><span class="n">splitext</span><span class="p">(</span><span class="n">files</span><span class="p">)[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="c" style="color: #60a0b0; font-style: italic;"># gets filename</span>
<span class="n">outFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">fileName</span> <span class="o" style="color: #666666;">+</span> <span class="s" style="color: #4070a0;">".jpg"</span>
<span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">save</span><span class="p">(</span><span class="n">outFile</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">fileName</span> <span class="o" style="color: #666666;">+</span> <span class="s" style="color: #4070a0;">" ... converted"</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="s" style="color: #4070a0;">"</span><span class="se" style="color: #4070a0; font-weight: bold;">\n</span><span class="s" style="color: #4070a0;">"</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">delOldFileTypes</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">types</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">FILETYPES</span><span class="p">:</span>
<span class="n">openFiles</span> <span class="o" style="color: #666666;">=</span> <span class="n">glob</span><span class="o" style="color: #666666;">.</span><span class="n">glob</span><span class="p">(</span><span class="n">types</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">files</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">openFiles</span><span class="p">:</span>
<span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">remove</span><span class="p">(</span><span class="n">files</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">files</span> <span class="o" style="color: #666666;">+</span> <span class="s" style="color: #4070a0;">" ... deleted"</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="s" style="color: #4070a0;">"</span><span class="se" style="color: #4070a0; font-weight: bold;">\n</span><span class="s" style="color: #4070a0;">"</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">resize</span><span class="p">():</span>
<span class="n">openFiles</span> <span class="o" style="color: #666666;">=</span> <span class="n">glob</span><span class="o" style="color: #666666;">.</span><span class="n">glob</span><span class="p">(</span><span class="s" style="color: #4070a0;">'*.jpg'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">files</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">openFiles</span><span class="p">:</span>
<span class="n">inFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">Image</span><span class="o" style="color: #666666;">.</span><span class="n">open</span><span class="p">(</span><span class="n">files</span><span class="p">)</span>
<span class="n">fileName</span> <span class="o" style="color: #666666;">=</span> <span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">path</span><span class="o" style="color: #666666;">.</span><span class="n">splitext</span><span class="p">(</span><span class="n">files</span><span class="p">)[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="c" style="color: #60a0b0; font-style: italic;"># gets filename</span>
<span class="n">outFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">fileName</span> <span class="o" style="color: #666666;">+</span> <span class="s" style="color: #4070a0;">".jpg"</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">fileName</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="s" style="color: #4070a0;">"Origonal size "</span><span class="p">,</span><span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">size</span>
<span class="n">xDim</span> <span class="o" style="color: #666666;">=</span> <span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">size</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span>
<span class="n">yDim</span> <span class="o" style="color: #666666;">=</span> <span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">size</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span>
<span class="n">newSize</span> <span class="o" style="color: #666666;">=</span> <span class="n">aspectRatio</span><span class="p">(</span><span class="n">xDim</span><span class="p">,</span> <span class="n">yDim</span><span class="p">)</span>
<span class="n">inFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">resize</span><span class="p">((</span><span class="nb" style="color: #007020;">int</span><span class="p">(</span><span class="n">newSize</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]),</span><span class="nb" style="color: #007020;">int</span><span class="p">(</span><span class="n">newSize</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">])),</span><span class="n">Image</span><span class="o" style="color: #666666;">.</span><span class="n">ANTIALIAS</span><span class="p">)</span>
<span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">save</span><span class="p">(</span><span class="n">outFile</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="s" style="color: #4070a0;">"New Size "</span><span class="p">,</span><span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">size</span><span class="p">,</span> <span class="s" style="color: #4070a0;">"</span><span class="se" style="color: #4070a0; font-weight: bold;">\n</span><span class="s" style="color: #4070a0;">"</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">aspectRatio</span><span class="p">(</span><span class="n">xDim</span><span class="p">,</span> <span class="n">yDim</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">xDim</span> <span class="o" style="color: #666666;"><=</span> <span class="n">NEWIMAGESIZE</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">yDim</span> <span class="o" style="color: #666666;"><=</span> <span class="n">NEWIMAGESIZE</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;">#ensures images already correct size are not enlarged.</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span><span class="p">(</span><span class="n">xDim</span><span class="p">,</span> <span class="n">yDim</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">xDim</span> <span class="o" style="color: #666666;">></span> <span class="n">yDim</span><span class="p">:</span>
<span class="n">divider</span> <span class="o" style="color: #666666;">=</span> <span class="n">xDim</span><span class="o" style="color: #666666;">/</span><span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">NEWIMAGESIZE</span><span class="p">)</span>
<span class="n">xDim</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">xDim</span><span class="o" style="color: #666666;">/</span><span class="n">divider</span><span class="p">)</span>
<span class="n">yDim</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">yDim</span><span class="o" style="color: #666666;">/</span><span class="n">divider</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span><span class="p">(</span><span class="n">xDim</span><span class="p">,</span> <span class="n">yDim</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">yDim</span> <span class="o" style="color: #666666;">></span> <span class="n">xDim</span><span class="p">:</span>
<span class="n">divider</span> <span class="o" style="color: #666666;">=</span> <span class="n">yDim</span><span class="o" style="color: #666666;">/</span><span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">NEWIMAGESIZE</span><span class="p">)</span>
<span class="n">xDim</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">xDim</span><span class="o" style="color: #666666;">/</span><span class="n">divider</span><span class="p">)</span>
<span class="n">yDim</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">yDim</span><span class="o" style="color: #666666;">/</span><span class="n">divider</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span><span class="p">(</span><span class="n">xDim</span><span class="p">,</span> <span class="n">yDim</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">xDim</span> <span class="o" style="color: #666666;">==</span> <span class="n">yDim</span><span class="p">:</span>
<span class="n">xDim</span> <span class="o" style="color: #666666;">=</span> <span class="n">NEWIMAGESIZE</span>
<span class="n">yDim</span> <span class="o" style="color: #666666;">=</span> <span class="n">NEWIMAGESIZE</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span><span class="p">(</span><span class="n">xDim</span><span class="p">,</span> <span class="n">yDim</span><span class="p">)</span>
<span class="n">convert2jpg</span><span class="p">()</span>
<span class="n">delOldFileTypes</span><span class="p">()</span>
<span class="n">resize</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="p">(</span><span class="s" style="color: #4070a0;">'All Done!!!'</span><span class="p">)</span>
<span class="nb" style="color: #007020;">raw_input</span><span class="p">(</span><span class="s" style="color: #4070a0;">'Images Resized... Press any key to continue'</span><span class="p">)</span></pre>
<br />
The first thing we need to do is to import three libraries, which are required for the program.<br />
<ul>
<li>Image - Helps us do certain things with the image files.</li>
<li>glob - Helps us with filenames when loading files.</li>
<li>os - Allows us to access operating system dependant functionality. </li>
</ul>
<div>
For those new to programming, these would not be the first lines I would type into my program, but are added as and when required. </div>
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #60a0b0; font-style: italic;">## Required Modules</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">Image</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">glob</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">os</span></pre>
<br />
Next I have assigned some Global Variables.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #60a0b0; font-style: italic;">## Global Variables</span>
<span class="n">FILETYPES</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="s" style="color: #4070a0;">'*.tiff'</span><span class="p">,</span><span class="s" style="color: #4070a0;">'*.jpeg'</span><span class="p">,</span><span class="s" style="color: #4070a0;">'*.png'</span><span class="p">]</span>
<span class="n">NEWIMAGESIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">400</span></pre>
<br />
<ul>
<li>FILETYPES - This is a list of the types of files our program will look for. </li>
<li>NEWIMAGESIZE - This is the maximum number of pixels in either X or Y that our image will become. </li>
</ul>
The advantage of global variables is you can change the value in one location, and it will be changed throughout your program.<br />
<br />
Now we will write the first of the four functions in our program. The first function converts the images to .jpg format.<br />
<br />
Lets look at the whole function, and then I will break it down line by line.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #60a0b0; font-style: italic;">## Functions</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">convert2jpg</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">types</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">FILETYPES</span><span class="p">:</span>
<span class="n">openFiles</span> <span class="o" style="color: #666666;">=</span> <span class="n">glob</span><span class="o" style="color: #666666;">.</span><span class="n">glob</span><span class="p">(</span><span class="n">types</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">files</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">openFiles</span><span class="p">:</span>
<span class="n">inFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">Image</span><span class="o" style="color: #666666;">.</span><span class="n">open</span><span class="p">(</span><span class="n">files</span><span class="p">)</span>
<span class="n">fileName</span> <span class="o" style="color: #666666;">=</span> <span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">path</span><span class="o" style="color: #666666;">.</span><span class="n">splitext</span><span class="p">(</span><span class="n">files</span><span class="p">)[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="c" style="color: #60a0b0; font-style: italic;"># gets filename</span>
<span class="n">outFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">fileName</span> <span class="o" style="color: #666666;">+</span> <span class="s" style="color: #4070a0;">".jpg"</span>
<span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">save</span><span class="p">(</span><span class="n">outFile</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">fileName</span> <span class="o" style="color: #666666;">+</span> <span class="s" style="color: #4070a0;">" ... converted"</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="s" style="color: #4070a0;">"</span><span class="se" style="color: #4070a0; font-weight: bold;">\n</span><span class="s" style="color: #4070a0;">"</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
The first line defines our function. It names the function and, as the brackets are empty, states we are not passing anything into the function.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">convert2jpg</span><span class="p">():</span></pre>
<br />
Earlier we created a global variable, which was a list of all the filetypes we wanted our program to work on. The next line iterates through that list one filetype at a time.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">types</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">FILETYPES</span><span class="p">:</span></pre>
<br />
Next we use the glob module, which we imported at the start of our program, to create a list of all the filenames associated with the current 'type' of file we are dealing with. For example, if we are currently running through the FILETYPES and are currently looking at the .tiff files, openFiles will become a list of all the .tiff files in our folder.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">openFiles</span> <span class="o" style="color: #666666;">=</span> <span class="n">glob</span><span class="o" style="color: #666666;">.</span><span class="n">glob</span><span class="p">(</span><span class="n">types</span><span class="p">)</span></pre>
<br />
Now we have our list of files associated with the current file type, we can start to do something with them. The next line iterates through each of the file names, in the list, one at a time.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">files</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">openFiles</span><span class="p">:</span></pre>
<br />
We then use the Image module to open the file.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">inFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">Image</span><span class="o" style="color: #666666;">.</span><span class="n">open</span><span class="p">(</span><span class="n">files</span><span class="p">)</span> </pre>
<br />
The next line, although it looks complicated, isn't at all.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">fileName</span> <span class="o" style="color: #666666;">=</span> <span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">path</span><span class="o" style="color: #666666;">.</span><span class="n">splitext</span><span class="p">(</span><span class="n">files</span><span class="p">)[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="c" style="color: #60a0b0; font-style: italic;"># gets filename</span></pre>
<br />
Lets look at the individual aspects of this line:<br />
<ul>
<li>os.path.splitext(files) - Splits the filename from the extension. This creates a list containing [filename , extension]. This uses the os module we imported at the start of our program. </li>
<li>[0] - Ensures we only take the first part of the list. i.e. the filename, and not the extension. </li>
<li>fileName - A variable we store the result in. </li>
</ul>
<div>
See I said it was not difficult!</div>
<div>
<br /></div>
<div>
Now we create the name of the file we will be saving. This will be the same as the current filename, but with a different extension. </div>
<div>
<br /></div>
<div>
</div>
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">outFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">fileName</span> <span class="o" style="color: #666666;">+</span> <span class="s" style="color: #4070a0;">".jpg"</span> </pre>
<br />
Then we save the file we opened with the new name.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">save</span><span class="p">(</span><span class="n">outFile</span><span class="p">)</span></pre>
<br />
We now print the fileName and the words " ... converted" to the screen so we can see which files have been converted.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">fileName</span> <span class="o" style="color: #666666;">+</span> <span class="s" style="color: #4070a0;">" ... converted"</span></pre>
<br />
Finally we print a blank line, and exit from the function.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="s" style="color: #4070a0;">"</span><span class="se" style="color: #4070a0; font-weight: bold;">\n</span><span class="s" style="color: #4070a0;">"</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
Remember that we have a few nested for loops in our function. So we will only get to these two lines once we have been through all iterations within the for loops.<br />
<br />
Now we move into the second function in our program, which is to delete the original files. The full function is as follows.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">delOldFileTypes</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">types</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">FILETYPES</span><span class="p">:</span>
<span class="n">openFiles</span> <span class="o" style="color: #666666;">=</span> <span class="n">glob</span><span class="o" style="color: #666666;">.</span><span class="n">glob</span><span class="p">(</span><span class="n">types</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">files</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">openFiles</span><span class="p">:</span>
<span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">remove</span><span class="p">(</span><span class="n">files</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">files</span> <span class="o" style="color: #666666;">+</span> <span class="s" style="color: #4070a0;">" ... deleted"</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="s" style="color: #4070a0;">"</span><span class="se" style="color: #4070a0; font-weight: bold;">\n</span><span class="s" style="color: #4070a0;">"</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
The first thing you will see is there are a lot of similarities between this function and the previous. It would be possible to add the additional functionality, of deleting the files, into the first function. However I have decided to keep it separate, as this allows greater flexibility in my program. I may not always call the function to delete the old files.<br />
<br />
The difference between the functions occurs in the inner for loop.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">files</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">openFiles</span><span class="p">:</span>
<span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">remove</span><span class="p">(</span><span class="n">files</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">files</span> <span class="o" style="color: #666666;">+</span> <span class="s" style="color: #4070a0;">" ... deleted"</span></pre>
<br />
Rather than saving the files as a different type, we instead use<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">remove</span><span class="p">(</span><span class="n">files</span><span class="p">)</span></pre>
<br />
to delete the files, and then print some information saying the files have been deleted.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">files</span> <span class="o" style="color: #666666;">+</span> <span class="s" style="color: #4070a0;">" ... deleted"</span></pre>
<br />
Onto our third function.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">resize</span><span class="p">():</span>
<span class="n">openFiles</span> <span class="o" style="color: #666666;">=</span> <span class="n">glob</span><span class="o" style="color: #666666;">.</span><span class="n">glob</span><span class="p">(</span><span class="s" style="color: #4070a0;">'*.jpg'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">files</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">openFiles</span><span class="p">:</span>
<span class="n">inFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">Image</span><span class="o" style="color: #666666;">.</span><span class="n">open</span><span class="p">(</span><span class="n">files</span><span class="p">)</span>
<span class="n">fileName</span> <span class="o" style="color: #666666;">=</span> <span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">path</span><span class="o" style="color: #666666;">.</span><span class="n">splitext</span><span class="p">(</span><span class="n">files</span><span class="p">)[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="c" style="color: #60a0b0; font-style: italic;"># gets filename</span>
<span class="n">outFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">fileName</span> <span class="o" style="color: #666666;">+</span> <span class="s" style="color: #4070a0;">".jpg"</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">fileName</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="s" style="color: #4070a0;">"Origonal size "</span><span class="p">,</span><span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">size</span>
<span class="n">xDim</span> <span class="o" style="color: #666666;">=</span> <span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">size</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span>
<span class="n">yDim</span> <span class="o" style="color: #666666;">=</span> <span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">size</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span>
<span class="n">newSize</span> <span class="o" style="color: #666666;">=</span> <span class="n">aspectRatio</span><span class="p">(</span><span class="n">xDim</span><span class="p">,</span> <span class="n">yDim</span><span class="p">)</span>
<span class="n">inFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">resize</span><span class="p">((</span><span class="nb" style="color: #007020;">int</span><span class="p">(</span><span class="n">newSize</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]),</span><span class="nb" style="color: #007020;">int</span><span class="p">(</span><span class="n">newSize</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">])),</span><span class="n">Image</span><span class="o" style="color: #666666;">.</span><span class="n">ANTIALIAS</span><span class="p">)</span>
<span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">save</span><span class="p">(</span><span class="n">outFile</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="s" style="color: #4070a0;">"New Size "</span><span class="p">,</span><span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">size</span><span class="p">,</span> <span class="s" style="color: #4070a0;">"</span><span class="se" style="color: #4070a0; font-weight: bold;">\n</span><span class="s" style="color: #4070a0;">"</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
Now that we have changed the file type and deleted the old files we can resize the files.<br />
<br />
Again the start of the function is similar to what we have seen previously, although we are only working with .jpg files and not other types, so only need one for loop.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">resize</span><span class="p">():</span>
<span class="n">openFiles</span> <span class="o" style="color: #666666;">=</span> <span class="n">glob</span><span class="o" style="color: #666666;">.</span><span class="n">glob</span><span class="p">(</span><span class="s" style="color: #4070a0;">'*.jpg'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">files</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">openFiles</span><span class="p">:</span>
<span class="n">inFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">Image</span><span class="o" style="color: #666666;">.</span><span class="n">open</span><span class="p">(</span><span class="n">files</span><span class="p">)</span>
<span class="n">fileName</span> <span class="o" style="color: #666666;">=</span> <span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">path</span><span class="o" style="color: #666666;">.</span><span class="n">splitext</span><span class="p">(</span><span class="n">files</span><span class="p">)[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="c" style="color: #60a0b0; font-style: italic;"># gets filename</span>
<span class="n">outFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">fileName</span> <span class="o" style="color: #666666;">+</span> <span class="s" style="color: #4070a0;">".jpg"</span></pre>
<br />
There is nothing new in that section of the program.<br />
<br />
We then print the file name to the screen, and also the size of the original file, which will allow us to compare with the final file size later.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">fileName</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="s" style="color: #4070a0;">"Origonal size "</span><span class="p">,</span><span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">size</span></pre>
<br />
infile.size gives the number of pixels in the image in the format (xPixels, yPixels), which is a handy reference.<br />
<br />
We then separate the X and the Y number of pixels and store them in their own variables, xDim and yDim.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">xDim</span> <span class="o" style="color: #666666;">=</span> <span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">size</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span>
<span class="n">yDim</span> <span class="o" style="color: #666666;">=</span> <span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">size</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> </pre>
<br />
We send these to another function, whose purpose is to maintain the correct aspect ratio of the image, after is has been resized. We will look at this function in more detail in a minute.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">newSize</span> <span class="o" style="color: #666666;">=</span> <span class="n">aspectRatio</span><span class="p">(</span><span class="n">xDim</span><span class="p">,</span> <span class="n">yDim</span><span class="p">)</span> </pre>
<br />
The result is stored in a variable called newSize.<br />
<br />
Using our new size of image we can resize the image.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">inFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">resize</span><span class="p">((</span><span class="nb" style="color: #007020;">int</span><span class="p">(</span><span class="n">newSize</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]),</span><span class="nb" style="color: #007020;">int</span><span class="p">(</span><span class="n">newSize</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">])),</span><span class="n">Image</span><span class="o" style="color: #666666;">.</span><span class="n">ANTIALIAS</span><span class="p">)</span></pre>
<br />
This resizes the current inFile and saves the result also as inFile using the resize command. Effectively overwriting what is being stored as inFile.<br />
<br />
It looks a little complicated to the right of resize, but it isn't.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="p">(</span><span class="nb" style="color: #007020;">int</span><span class="p">(</span><span class="n">newSize</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]),</span><span class="nb" style="color: #007020;">int</span><span class="p">(</span><span class="n">newSize</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]))</span></pre>
<br />
This refers to the size that we want to resize the image to, in the format (X dimension ,Y dimension).<br />
<ul>
<li>newsize[0] takes the first item from the newSize list, which is the X value, and then ensures it is a whole number by converting it to an integer (int).</li>
<li>newsize[1] does the same for the Y value. </li>
</ul>
<br />
Finally Image.ANTIALIAS improves the image quality. What exactly AntiAlias does is outside the scope of this blog!<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">save</span><span class="p">(</span><span class="n">outFile</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="s" style="color: #4070a0;">"New Size "</span><span class="p">,</span><span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">size</span><span class="p">,</span> <span class="s" style="color: #4070a0;">"</span><span class="se" style="color: #4070a0; font-weight: bold;">\n</span><span class="s" style="color: #4070a0;">"</span></pre>
<br />
Next we save the file, and again print some information showing the new file size.<br />
<br />
We then return from the function.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
The fourth function is the function we referred to in the third function, the apectRatio function. As always lets look at the full function and then break it down into more detail.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">aspectRatio</span><span class="p">(</span><span class="n">xDim</span><span class="p">,</span> <span class="n">yDim</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">xDim</span> <span class="o" style="color: #666666;"><=</span> <span class="n">NEWIMAGESIZE</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">yDim</span> <span class="o" style="color: #666666;"><=</span> <span class="n">NEWIMAGESIZE</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;">#ensures images already correct size are not enlarged.</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span><span class="p">(</span><span class="n">xDim</span><span class="p">,</span> <span class="n">yDim</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">xDim</span> <span class="o" style="color: #666666;">></span> <span class="n">yDim</span><span class="p">:</span>
<span class="n">divider</span> <span class="o" style="color: #666666;">=</span> <span class="n">xDim</span><span class="o" style="color: #666666;">/</span><span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">NEWIMAGESIZE</span><span class="p">)</span>
<span class="n">xDim</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">xDim</span><span class="o" style="color: #666666;">/</span><span class="n">divider</span><span class="p">)</span>
<span class="n">yDim</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">yDim</span><span class="o" style="color: #666666;">/</span><span class="n">divider</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span><span class="p">(</span><span class="n">xDim</span><span class="p">,</span> <span class="n">yDim</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">yDim</span> <span class="o" style="color: #666666;">></span> <span class="n">xDim</span><span class="p">:</span>
<span class="n">divider</span> <span class="o" style="color: #666666;">=</span> <span class="n">yDim</span><span class="o" style="color: #666666;">/</span><span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">NEWIMAGESIZE</span><span class="p">)</span>
<span class="n">xDim</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">xDim</span><span class="o" style="color: #666666;">/</span><span class="n">divider</span><span class="p">)</span>
<span class="n">yDim</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">yDim</span><span class="o" style="color: #666666;">/</span><span class="n">divider</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span><span class="p">(</span><span class="n">xDim</span><span class="p">,</span> <span class="n">yDim</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">xDim</span> <span class="o" style="color: #666666;">==</span> <span class="n">yDim</span><span class="p">:</span>
<span class="n">xDim</span> <span class="o" style="color: #666666;">=</span> <span class="n">NEWIMAGESIZE</span>
<span class="n">yDim</span> <span class="o" style="color: #666666;">=</span> <span class="n">NEWIMAGESIZE</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span><span class="p">(</span><span class="n">xDim</span><span class="p">,</span> <span class="n">yDim</span><span class="p">)</span></pre>
<br />
<br />
Firstly why is this function needed? Well, if you are resizing images, you need to maintain the ratio between the X and the Y dimension, otherwise the image will look distorted. This function helps work out what the new values should be, ensuring a good relationship is maintained.<br />
<br />
First of all we define the function name, and pass in the current size of the image, xDim and yDim.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">aspectRatio</span><span class="p">(</span><span class="n">xDim</span><span class="p">,</span> <span class="n">yDim</span><span class="p">):</span></pre>
<br />
Right at the start of our program we created a global variable called NEWIMAGESIZE. This defined the largest value, in terms of the number of pixels in either X or Y, that our resized image should have.<br />
<br />
The first two lines checks if either the X or Y dimension of our image is less than or equal to (<=) NEWIMAGESIZE. If it is, then we don't need to modify the size of our image.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">xDim</span> <span class="o" style="color: #666666;"><=</span> <span class="n">NEWIMAGESIZE</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">yDim</span> <span class="o" style="color: #666666;"><=</span> <span class="n">NEWIMAGESIZE</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;">#ensures images already correct size are not enlarged.</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span><span class="p">(</span><span class="n">xDim</span><span class="p">,</span> <span class="n">yDim</span><span class="p">)</span></pre>
<br />
We just return xDim and yDim unchanged.<br />
<br />
We now do another check using elif (else if).<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">xDim</span> <span class="o" style="color: #666666;">></span> <span class="n">yDim</span><span class="p">:</span></pre>
<br />
This checks to see if the image is a landscape image i.e. there are more pixels in X than in Y.<br />
<br />
If this statement is true, we need to reduce the X size down to the value in NEWIMAGESIZE. We can do this by dividing xDim by a value we will store in a variable called divider. Firstly we need to determine the value of divider.<br />
<br />
By dividing the size of X (xDim) by the value we need it to become, i.e. NEWIMAGESIZE, we get a the value of divider, we can use this to determine the new size of X and Y. I have also made this a float to ensure some decimal points for accuracy.<br />
<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">divider</span> <span class="o" style="color: #666666;">=</span> <span class="n">xDim</span><span class="o" style="color: #666666;">/</span><span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">NEWIMAGESIZE</span><span class="p">)</span></pre>
<br />
It figures if we now take xDim and divide it by our value stored in divider, we will get a new value of xDim, which should be the same as the value in NEWIMAGESIZE.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">xDim</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">xDim</span><span class="o" style="color: #666666;">/</span><span class="n">divider</span><span class="p">)</span>
<span class="n">yDim</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">yDim</span><span class="o" style="color: #666666;">/</span><span class="n">divider</span><span class="p">)</span></pre>
<br />
If we also divide yDIM by divider, we will get a new value of yDim. As yDim was smaller than xDim, then it follows that the new value of yDim should be less than NEWIMAGESIZE.<br />
<br />
As both xDim and yDim have been divided by the same value, they will maintain the same aspect ratio as the original image.<br />
<br />
Now we just return the values of xDim and yDim.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">return</span><span class="p">(</span><span class="n">xDim</span><span class="p">,</span> <span class="n">yDim</span><span class="p">)</span></pre>
<br />
The next section is almost identical.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">yDim</span> <span class="o" style="color: #666666;">></span> <span class="n">xDim</span><span class="p">:</span>
<span class="n">divider</span> <span class="o" style="color: #666666;">=</span> <span class="n">yDim</span><span class="o" style="color: #666666;">/</span><span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">NEWIMAGESIZE</span><span class="p">)</span>
<span class="n">xDim</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">xDim</span><span class="o" style="color: #666666;">/</span><span class="n">divider</span><span class="p">)</span>
<span class="n">yDim</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">yDim</span><span class="o" style="color: #666666;">/</span><span class="n">divider</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span><span class="p">(</span><span class="n">xDim</span><span class="p">,</span> <span class="n">yDim</span><span class="p">)</span></pre>
<br />
However this is for the case where the image is larger in Y than X. i.e. the image is portrait rather than landscape. In this case we want the yDim to become equal to the size of NEWSIZEIMAGE. Therefore yDim is used to calculate the value of divider.<br />
<br />
The final section covers if the image is square. In that case both xDim and yDim can be made equal to NEWSIZEIMAGE.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">xDim</span> <span class="o" style="color: #666666;">==</span> <span class="n">yDim</span><span class="p">:</span>
<span class="n">xDim</span> <span class="o" style="color: #666666;">=</span> <span class="n">NEWIMAGESIZE</span>
<span class="n">yDim</span> <span class="o" style="color: #666666;">=</span> <span class="n">NEWIMAGESIZE</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span><span class="p">(</span><span class="n">xDim</span><span class="p">,</span> <span class="n">yDim</span><span class="p">)</span></pre>
<br />
Right that is all the functions written. We now just have to call them.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">convert2jpg</span><span class="p">()</span>
<span class="n">delOldFileTypes</span><span class="p">()</span>
<span class="n">resize</span><span class="p">()</span></pre>
<br />
Finally I have added a message to say that everything is complete, and asking for the user to press a key to continue.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.6000003814697px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="p">(</span><span class="s" style="color: #4070a0;">'All Done!!!'</span><span class="p">)</span>
<span class="nb" style="color: #007020;">raw_input</span><span class="p">(</span><span class="s" style="color: #4070a0;">'Images Resized... Press any key to continue'</span><span class="p">)</span></pre>
<div>
<span class="p"><br /></span></div>
<div>
<span class="p">That brings us to the end of the program. </span><br />
<span class="p"><br /></span>
<span class="p">I hope you have found this blog post useful. It is certainly a Python program that is my first port of call when I need to resize images.</span></div>
</div>
Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com0tag:blogger.com,1999:blog-8250429656532783188.post-24096574180699887422014-08-18T12:30:00.000+01:002015-09-29T21:26:23.199+01:00Useful Python ResourcesBelow is a list of Python Resources which I have found during my continuous journey of learning Python.<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
I will keep adding to this list as I find more useful resources, so please, if you have anything you would like me to add to this list, then let me know. I would love to hear you comments on any of the resources listed below.<br />
<br />
<a href="http://python.org/">Python.org</a><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://www.python.org/static/img/python-logo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://www.python.org/static/img/python-logo.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The main Python website, loads of useful information on here. </div>
<br />
<a href="http://www.pygame.org/">Pygame.org</a><br />
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.pygame.org/docs/pygame_logo.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://www.pygame.org/docs/pygame_logo.gif" height="94" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
This website introduces you to a set of modules designed for writing games in Python. I have written a couple of blogs which will help you get started in Pygame.<br />
<br />
<ul>
<li><a href="http://trevorappleton.blogspot.co.uk/2014/04/writing-pong-using-python-and-pygame.html" target="_blank">Writing Pong with Pygame</a></li>
<li><a href="http://trevorappleton.blogspot.co.uk/2013/07/python-game-of-life.html" target="_blank">Writing Game of Life with Pygame</a></li>
<li><a href="http://trevorappleton.blogspot.co.uk/2013/10/guide-to-creating-sudoku-solver-using.html" target="_blank">Writing a Sudoku Solver with Pygame</a></li>
</ul>
<br />
<br />
<a href="http://inventwithpython.com/" target="_blank">inventwithpython.com</a><br />
<div style="text-align: center;">
<div class="separator" style="clear: both; text-align: center;">
</div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://inventwithpython.com/images/header_invent.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="71" src="https://inventwithpython.com/images/header_invent.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="" style="clear: both; text-align: left;">
For me this was the best way to learn Python. By the time I was through the "Invent Your Own Games With Python" I was well on my way to being able to program in Python. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="https://www.edx.org/course/mitx/mitx-6-00-1x-introduction-computer-2841#.U-eH3YBdUmY" target="_blank">Edx - Introduction to Computer Science and Programming Using Python. </a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://www.edx.org/sites/default/files/course/image/banner/6.00x-detail-banner_2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="111" src="https://www.edx.org/sites/default/files/course/image/banner/6.00x-detail-banner_2.jpg" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
More involved than I was initially expecting, and the online material had a few hiccups which I am sure are now ironed out. Great fun and looked into many concepts of Computer Science. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="http://learnpythonthehardway.org/book/" target="_blank">Learn Python the Hard Way</a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: left;">
A free on-line book. Not one I have used, but have heard a lot of positives about it.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="http://www.codecademy.com/">codecademy.com</a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://cdn-production.codecademy.com/assets/logo/logo--dark-blue-bf11002ce1caecdfb9fec8d3286b8a8d.svg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://cdn-production.codecademy.com/assets/logo/logo--dark-blue-bf11002ce1caecdfb9fec8d3286b8a8d.svg" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Again not one I have used, but very good reviews from those who have. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="http://pythonbooks.revolunet.com/?utm_content=bufferecd11&utm_source=buffer&utm_medium=twitter&utm_campaign=Buffer">pythonbooks.revolunet.com</a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
A lot of free Python Books!</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="http://legacy.python.org/dev/peps/pep-0008/" target="_blank">PEP-0008</a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The official Style Guide for Python Programming. Definitely worth reading. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="http://www.swaroopch.com/notes/python/#preface" target="_blank">A Byte of Python</a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Another free on-line Python book.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="http://www.greenteapress.com/thinkpython/" target="_blank">Think Python</a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.greenteapress.com/thinkpython/think_python_comp2.medium.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://www.greenteapress.com/thinkpython/think_python_comp2.medium.png" height="200" width="151" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
How to think like a computer scientist. A free Python book introducing Python to beginners. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="http://overapi.com/python/?utm_content=buffer36e7d&utm_medium=social&utm_source=twitter.com&utm_campaign=buffer" target="_blank">Python Cheat Sheet</a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
A really handy Python cheat sheet to refer to. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com8tag:blogger.com,1999:blog-8250429656532783188.post-67643636236691381922014-06-09T12:20:00.000+01:002014-06-10T15:13:28.130+01:00Scheduling Python Programs using CronCron has become one of my favourite utilities in Linux. It allows you to schedule tasks to automatically happen at certain times. It is one of those tools that is so simple and so powerful, but all too often overlooked, or not known about.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWRpmYou37h96oPl8B3fKILr2u0KL_kWkMe8JtOou0B23YWhAC9b5NlVKvXkHWzSCCYARl9agfkLuMcD-CfXL467GYI-B3joDuf5psjmwvmvPoMwwgZ195CTDpeQlY-wS2jTN9UG1hO38/s1600/Crontab.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWRpmYou37h96oPl8B3fKILr2u0KL_kWkMe8JtOou0B23YWhAC9b5NlVKvXkHWzSCCYARl9agfkLuMcD-CfXL467GYI-B3joDuf5psjmwvmvPoMwwgZ195CTDpeQlY-wS2jTN9UG1hO38/s1600/Crontab.PNG" height="285" width="400" /></a></div>
<br />
<br />
I first stumbled across Cron when I decided to set up and administer a wiki server for the company I work for. There is a lot of data on the wiki and it is important that it gets backed up regularly.<br />
<br />
Initially I would take a dump of the MySQL database, and then copy the files over on a daily basis by hand.<br />
<br />
I then wrote a Python script which carried out these tasks for me. I just had to remember to run the script on a daily basis.<br />
<br />
Finally I automated this using Cron.<br />
<ul>
<li>Now every morning (Monday - Friday) at 1:00 am the company wiki is automatically backed up to two locations.</li>
<li>Secondly on the 1st of every Month at 2:00 am the wiki is automatically backed up to two different locations.</li>
</ul>
<br />
All this is done without me ever having to worry if it has been done. Cron looks after it all for me.<br />
<br />
What is more is it is very simple to use.<br />
<br />
This tutorial will help you get to grips with Cron and have your Raspberry Pi or any other Linux computer working away for you in the background.<br />
<br />
Firstly Cron does require the time on your Linux computer to be correct, otherwise tasks will not happen when you expect them to! Not that such a basic mistake would ever catch me out while writing this tutorial...<br />
<br />
So if you are using a Raspberry Pi, it might be worth setting the time at this point.<br />
<br />
type<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="go" style="color: #888888;">sudo raspi-config</span></pre>
<br />
into the command line.<br />
<br />
Then choose<br />
<br />
Internationalisation Options > Change Timezone > Europe > London<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwcMHsdkiYjkEIZPu-R-6O3SL_8ab6SR_MaVo7H2th0XES5OldtazB8Fi06Tt0RXRhnMA2Ny6heusqw3xeviHrr7G5UnLjntMerr5NRB6vhcrbyrNK9-_cHUrawluaVcWigkOhG7j68Rk/s1600/raspi-config.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwcMHsdkiYjkEIZPu-R-6O3SL_8ab6SR_MaVo7H2th0XES5OldtazB8Fi06Tt0RXRhnMA2Ny6heusqw3xeviHrr7G5UnLjntMerr5NRB6vhcrbyrNK9-_cHUrawluaVcWigkOhG7j68Rk/s1600/raspi-config.PNG" height="251" width="400" /></a></div>
<br />
<br />
for those of you in the UK. Obviously everyone else choose a location to suit your local timezone!<br />
<br />
For the purposes of this blog post we will assume you are wanting to run a Python program called test.py saved on your Desktop. If you want an example Python program to run then save the following as a Python program called test.py. When run this will create a new folder called test on your Desktop.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">os</span>
<span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">chdir</span><span class="p">(</span><span class="s" style="color: #4070a0;">"/home/pi/Desktop"</span><span class="p">)</span>
<span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">makedirs</span><span class="p">(</span><span class="s" style="color: #4070a0;">"test"</span><span class="p">)</span></pre>
<br />
Now again in your command line we will edit a file called crontab, this is short for Cron Tables, a place where you store all your actions.<br />
<br />
To edit crontab type the following into the command line.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="go" style="color: #888888;">sudo crontab -e</span></pre>
<br />
This will bring up a text file which looks as follows.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8kOF3W7YEy6K5tLtmtlgnqXd-1UXSK9X6QAZ5X7NQQPvVHjQis2uE3qAWKpW6fGA2oBjOnEy3L2rFZqTxEE6-k9NOsgpPNhRB6_1FCT8OP46e-xFMxJy169ppofnUtmPgO6xVcXSXS2E/s1600/Crontab.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8kOF3W7YEy6K5tLtmtlgnqXd-1UXSK9X6QAZ5X7NQQPvVHjQis2uE3qAWKpW6fGA2oBjOnEy3L2rFZqTxEE6-k9NOsgpPNhRB6_1FCT8OP46e-xFMxJy169ppofnUtmPgO6xVcXSXS2E/s1600/Crontab.PNG" height="285" width="400" /></a></div>
<br />
The majority of the text in this file briefly explains Cron and how to use it. The first thing you will notice is that all lines start with a #. This means these lines are ignored by Cron, they are for your reference only.<br />
<br />
While there are some basic instructions included in this file the most useful line is the bottom line.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="go" style="color: #888888;"># m h dom mon dow command</span></pre>
<br />
These are all explained in the file to mean the following.<br />
<ul>
<li>m - minute</li>
<li>h - hour</li>
<li>dom - day of month</li>
<li>mon - month</li>
<li>dow - day of week</li>
<li>command - This is the command you want to run.</li>
</ul>
<br />
Lets start with the command, as that's the easy bit.<br />
<br />
If you want to automatically run a Python program the command is made up of two parts.<br />
<br />
On the Raspberry Pi, if you are using Python 2.7, the first part of this will be as follows.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;">/usr/bin/python</pre>
<br />
or for Python 3<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;">/usr/bin/python3</pre>
<br />
The second part is a link to the Python program. For a program called test.py saved on your desktop you would need to have<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;">/home/pi/Desktop/test.py</pre>
<br />
These two parts are separated by a space to make up the command.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;">/usr/bin/python /home/pi/Desktop/test.py</pre>
<br />
These other parameters (m h dom mon dow) are what you will use to specify when your task will run. For each of them you can specify a number or if you want to use all possible values a * is used to signify this.<br />
<ul>
<li>The minutes can be numbers from 0 - 59 and indicates the minute in the hour you want the task to run.</li>
<li>The hours can be from 0 - 23 and indicates the hour you want the task to run.</li>
<li>Day of the month, 1-31, indicates the date within the month in which you would like to run the task.</li>
<li>Month, 1-12, indicates in which month you would like to run the task.</li>
<li>Day of the Week, 0-6, indicates on which day you would like to run the task. 0 is Sunday, 1 is Monday etc. </li>
</ul>
The secret to setting this correctly is to use a combination of these to define the schedule.<br />
<br />
If you wanted to run your python program every hour, then you would only have to supply a value for the minutes, specifying at what point in the hour you wanted your program to run. For example to run your program every 35 minutes past the hour you would enter the following into your crontab.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;">35 * * * * /usr/bin/python /home/pi/Desktop/test.py</pre>
<br />
The hours and minutes are easy to work out. If you want to run something everyday at 4:35 you would simply create a line in your crontab which would say.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;">35 4 * * * /usr/bin/python /home/pi/Desktop/test.py</pre>
<br />
Making this run on the 12th of the month only you would need to put the figure 12 into the day of the month field also.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;">35 4 12 * * /usr/bin/python /home/pi/Desktop/test.py</pre>
<br />
Taking this further you could specify that you only want your program to run at 4:35 on the 12th March.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;">35 4 12 3 * /usr/bin/python /home/pi/Desktop/test.py</pre>
<br />
Alternatively you may want to to run at 4:35 every Monday, so would need to use the Day of the week field. The numbers from 0 - 6 represent the days of the week. 0 is a Sunday, 1 is Monday etc.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;">35 4 * * 1 /usr/bin/python /home/pi/Desktop/test.py</pre>
<br />
We have put the Day of the Month and the Month back to being a * for this to happen, as we don't want to limit when our program to run on the 12th March only. Leaving these values in would only run the program on the 12th March at 4:35 if that day actually happened to be a Monday! The * implies it can run any day or month.<br />
<br />
Easy huh?<br />
<br />
There are a few other special characters which help you define when your program should run.<br />
<br />
A comma can be used to allow you to add more values into a field. For instance<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;">35 4 * * 1,4 /usr/bin/python /home/pi/Desktop/test.py</pre>
<br />
The 1,4 indicates the program will run on Monday and Thursday.<br />
<br />
Using a - allows you to choose a series of values.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;">35 4 * * 1-4 /usr/bin/python /home/pi/Desktop/test.py</pre>
<br />
The 1-4 indicates the program will run Monday - Thursday. ie. Monday, Tuesday, Wednesday and Thursday.<br />
<br />
Finally a / denotes increments of ranges.<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;">/15 * * * * /usr/bin/python /home/pi/Desktop/test.py</pre>
<br />
This will run the program every 15 minutes.<br />
<br />
One final useful command is<br />
<br />
<pre style="background: rgb(240, 240, 240); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;">@reboot /usr/bin/python /home/pi/Desktop/test.py</pre>
<br />
Will run the program when you reboot your Raspberry Pi or Computer.<br />
<br />
From these few examples you have seen that Cron gives you a huge amount of flexibility on when you schedule tasks.<br />
<br />
I hope you have found this blog post useful and that it will help you get started automating your programs.<br />
<br />
<br />
<br />
<br />
<br />
<br />Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com13tag:blogger.com,1999:blog-8250429656532783188.post-12623368070503273522014-04-17T12:07:00.000+01:002017-04-01T11:31:26.631+01:00Writing Pong using Python and PygameOk so imagine the year is 1973. All the talk is about a new arcade game which has been released by Atari. That game is called Pong.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://upload.wikimedia.org/wikipedia/commons/f/f8/Pong.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://upload.wikimedia.org/wikipedia/commons/f/f8/Pong.png" height="240" width="320" /></a></div>
<br />
<br />
Now it might not seem much of a game by today's standards, but it was a massive hit in its day... or so I am told.<br />
<br />
But don't be deceived, although a simple game, Pong covers a wide range of aspects of computer game programming. There is movement, control, collision detection, scoring, artificial intelligence. Its all in there!<br />
<br />
Being able to program Pong is a doorway to being able to program a lot of other games.<br />
<br />
However once you start playing Pong you might find less time to program, as it is quite addictive!<br />
<br />
We are going to program pong using Python and Pygame.<br />
<br />
I will be using Python 2.7. For those programming on a Raspberry Pi this will already be installed. Just ensure you click on the IDLE icon and not the IDLE3 icon. If Python 2.7 is not installed on your system you may have to install it from the Python website, just follow the link below.<br />
<br />
<div style="text-align: center;">
<a href="https://www.python.org/downloads/">https://www.python.org/downloads/</a></div>
<div style="text-align: center;">
<br /></div>
Pygame is a basically a set of modules which are designed to help you write computer games. We will be using some of these modules throughout this tutorial. You will need to install Pygame, which is free, and runs on Windows, Linux and Mac OSX (plus many more operating systems!)<br />
<br />
If you are programming on a Raspberry Pi, again this is already installed, if not to download Pygame go to the Pygame website.<br />
<br />
<div style="text-align: center;">
<a href="http://www.pygame.org/">www.pygame.org</a></div>
<br />
One final comment before we get into the programming, on the Raspberry Pi desktop there is a Python Games icon. This links you to a website by Al Sweigart who has written several Python books including one on Pygame. If you are new to Python then check out his books.<br />
<br />
<div style="text-align: center;">
<a href="http://inventwithpython.com/">http://inventwithpython.com</a>/</div>
<br />
I cannot rate them highly enough! After several false starts with other books, it was these resources that taught me Python.<br />
<br />
Ok that's enough pre-amble, lets get on with it.<br />
<br />
I am going to break this game down into stages, which reflect how I developed it. I hope this will show you that when you look at the game as a whole it can seem daunting, but when broken down it is just made up of many easy parts.<br />
<br />
So the stages we will follow are:<br />
<br />
Stage 1 - Create a blank screen<br />
Stage 2 - Draw the arena, the paddles and the ball<br />
Stage 3 - Move the ball around<br />
Stage 4 - Check for a collision with all edges<br />
Stage 5 - Move the players paddle<br />
Stage 6 - Move the computers paddle with Artificial Intelligence<br />
Stage 7 - Check for a collision with the paddles<br />
Stage 8 - Add a scoring system<br />
Stage 9 - Finally we will look at methods to increase the speed for slower computers<br />
<br />
As we go through this tutorial I will provide the whole of the code at the beginning. To help you isolate each stage I will also provide the complete code for that stage as we get to it. I will also tell you where to type each line and include the code you need to type. Where I feel it necessary I will add additional lines in with the code to help you understand where you should type the code. You can always refer to the source code of the complete program or the source code of that stage for further guidance.<br />
<br />
First of all, as promised, I will show you the whole code. At this stage don't worry if you don't understand it all. I would suggest having a read through it and seeing what parts you understand and which you don't.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: green; font-weight: bold;">import</span> <span class="nn" style="color: blue; font-weight: bold;">pygame</span><span class="o" style="color: #666666;">,</span> <span class="nn" style="color: blue; font-weight: bold;">sys</span>
<span class="kn" style="color: green; font-weight: bold;">from</span> <span class="nn" style="color: blue; font-weight: bold;">pygame.locals</span> <span class="kn" style="color: green; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="c" style="color: #408080; font-style: italic;"># Number of frames per second</span>
<span class="c" style="color: #408080; font-style: italic;"># Change this value to speed up or slow down your game</span>
<span class="n">FPS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">200</span>
<span class="c" style="color: #408080; font-style: italic;">#Global Variables to be used through our program</span>
<span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">400</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">300</span>
<span class="n">LINETHICKNESS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">10</span>
<span class="n">PADDLESIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">50</span>
<span class="n">PADDLEOFFSET</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">20</span>
<span class="c" style="color: #408080; font-style: italic;"># Set up the colours</span>
<span class="n">BLACK</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #666666;">0</span> <span class="p">,</span><span class="mi" style="color: #666666;">0</span> <span class="p">,</span><span class="mi" style="color: #666666;">0</span> <span class="p">)</span>
<span class="n">WHITE</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #666666;">255</span><span class="p">,</span><span class="mi" style="color: #666666;">255</span><span class="p">,</span><span class="mi" style="color: #666666;">255</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the arena the game will be played in. </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawArena</span><span class="p">():</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">((</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">))</span>
<span class="c" style="color: #408080; font-style: italic;">#Draw outline of arena</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">),(</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">)),</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #666666;">2</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draw centre line</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">),</span><span class="mi" style="color: #666666;">0</span><span class="p">),((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">),</span><span class="n">WINDOWHEIGHT</span><span class="p">),</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">4</span><span class="p">))</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the paddle</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawPaddle</span><span class="p">(</span><span class="n">paddle</span><span class="p">):</span>
<span class="c" style="color: #408080; font-style: italic;">#Stops paddle moving too low</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span>
<span class="c" style="color: #408080; font-style: italic;">#Stops paddle moving too high</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">=</span> <span class="n">LINETHICKNESS</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws paddle</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">paddle</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#draws the ball</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">):</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">ball</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#moves the ball returns new position</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">moveBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">):</span>
<span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">x</span> <span class="o" style="color: #666666;">+=</span> <span class="n">ballDirX</span>
<span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="n">ballDirY</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">ball</span>
<span class="c" style="color: #408080; font-style: italic;">#Checks for a collision with a wall, and 'bounces' ball off it.</span>
<span class="c" style="color: #408080; font-style: italic;">#Returns new direction</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">checkEdgeCollision</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">):</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="p">)</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">or</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">):</span>
<span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirY</span> <span class="o" style="color: #666666;">*</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="p">)</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">or</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">):</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">*</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span>
<span class="c" style="color: #408080; font-style: italic;">#Checks is the ball has hit a paddle, and 'bounces' ball off it. </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">checkHitBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">paddle1</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">):</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #666666;">1</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;">==</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span> <span class="k" style="color: green; font-weight: bold;">return</span> <span class="mi" style="color: #666666;">1</span>
<span class="c" style="color: #408080; font-style: italic;">#Checks to see if a point has been scored returns new score</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">checkPointScored</span><span class="p">(</span><span class="n">paddle1</span><span class="p">,</span> <span class="n">ball</span><span class="p">,</span> <span class="n">score</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">):</span>
<span class="c" style="color: #408080; font-style: italic;">#reset points if left wall is hit</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;">==</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="mi" style="color: #666666;">0</span>
<span class="c" style="color: #408080; font-style: italic;">#1 point for hitting the ball</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span><span class="p">:</span>
<span class="n">score</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">score</span>
<span class="c" style="color: #408080; font-style: italic;">#5 points for beating the other paddle</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">score</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">5</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">score</span>
<span class="c" style="color: #408080; font-style: italic;">#if no points scored, return score unchanged</span>
<span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span> <span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">score</span>
<span class="c" style="color: #408080; font-style: italic;">#Artificial Intelligence of computer player </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">artificialIntelligence</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">):</span>
<span class="c" style="color: #408080; font-style: italic;">#If ball is moving away from paddle, center bat</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;"><</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">):</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;">></span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">):</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">-=</span> <span class="mi" style="color: #666666;">1</span>
<span class="c" style="color: #408080; font-style: italic;">#if ball moving towards bat, track its movement. </span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #666666;">1</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span><span class="p">:</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">-=</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">paddle2</span>
<span class="c" style="color: #408080; font-style: italic;">#Displays the current score on the screen</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">displayScore</span><span class="p">(</span><span class="n">score</span><span class="p">):</span>
<span class="n">resultSurf</span> <span class="o" style="color: #666666;">=</span> <span class="n">BASICFONT</span><span class="o" style="color: #666666;">.</span><span class="n">render</span><span class="p">(</span><span class="s" style="color: #ba2121;">'Score = </span><span class="si" style="color: #bb6688; font-style: italic; font-weight: bold;">%s</span><span class="s" style="color: #ba2121;">'</span> <span class="o" style="color: #666666;">%</span><span class="p">(</span><span class="n">score</span><span class="p">),</span> <span class="bp" style="color: green;">True</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">)</span>
<span class="n">resultRect</span> <span class="o" style="color: #666666;">=</span> <span class="n">resultSurf</span><span class="o" style="color: #666666;">.</span><span class="n">get_rect</span><span class="p">()</span>
<span class="n">resultRect</span><span class="o" style="color: #666666;">.</span><span class="n">topleft</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="mi" style="color: #666666;">150</span><span class="p">,</span> <span class="mi" style="color: #666666;">25</span><span class="p">)</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">blit</span><span class="p">(</span><span class="n">resultSurf</span><span class="p">,</span> <span class="n">resultRect</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Main function</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">main</span><span class="p">():</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">init</span><span class="p">()</span>
<span class="k" style="color: green; font-weight: bold;">global</span> <span class="n">DISPLAYSURF</span>
<span class="c" style="color: #408080; font-style: italic;">##Font information</span>
<span class="k" style="color: green; font-weight: bold;">global</span> <span class="n">BASICFONT</span><span class="p">,</span> <span class="n">BASICFONTSIZE</span>
<span class="n">BASICFONTSIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">20</span>
<span class="n">BASICFONT</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">font</span><span class="o" style="color: #666666;">.</span><span class="n">Font</span><span class="p">(</span><span class="s" style="color: #ba2121;">'freesansbold.ttf'</span><span class="p">,</span> <span class="n">BASICFONTSIZE</span><span class="p">)</span>
<span class="n">FPSCLOCK</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">time</span><span class="o" style="color: #666666;">.</span><span class="n">Clock</span><span class="p">()</span>
<span class="n">DISPLAYSURF</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_mode</span><span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_caption</span><span class="p">(</span><span class="s" style="color: #ba2121;">'Pong'</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Initiate variable and set starting positions</span>
<span class="c" style="color: #408080; font-style: italic;">#any future changes made within rectangles</span>
<span class="n">ballX</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">ballY</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">playerOnePosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">playerTwoPosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">score</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">0</span>
<span class="c" style="color: #408080; font-style: italic;">#Keeps track of ball direction</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="c" style="color: #408080; font-style: italic;">## -1 = left 1 = right</span>
<span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="c" style="color: #408080; font-style: italic;">## -1 = up 1 = down</span>
<span class="c" style="color: #408080; font-style: italic;">#Creates Rectangles for ball and paddles.</span>
<span class="n">paddle1</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">PADDLEOFFSET</span><span class="p">,</span><span class="n">playerOnePosition</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span><span class="n">PADDLESIZE</span><span class="p">)</span>
<span class="n">paddle2</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLEOFFSET</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">,</span> <span class="n">playerTwoPosition</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span><span class="n">PADDLESIZE</span><span class="p">)</span>
<span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">ballX</span><span class="p">,</span> <span class="n">ballY</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the starting position of the Arena</span>
<span class="n">drawArena</span><span class="p">()</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle1</span><span class="p">)</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle2</span><span class="p">)</span>
<span class="n">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">)</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">mouse</span><span class="o" style="color: #666666;">.</span><span class="n">set_visible</span><span class="p">(</span><span class="mi" style="color: #666666;">0</span><span class="p">)</span> <span class="c" style="color: #408080; font-style: italic;"># make cursor invisible</span>
<span class="k" style="color: green; font-weight: bold;">while</span> <span class="bp" style="color: green;">True</span><span class="p">:</span> <span class="c" style="color: #408080; font-style: italic;">#main game loop</span>
<span class="k" style="color: green; font-weight: bold;">for</span> <span class="n">event</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">in</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">():</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">QUIT</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">quit</span><span class="p">()</span>
<span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span>
<span class="c" style="color: #408080; font-style: italic;"># mouse movement commands</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">MOUSEMOTION</span><span class="p">:</span>
<span class="n">mousex</span><span class="p">,</span> <span class="n">mousey</span> <span class="o" style="color: #666666;">=</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">pos</span>
<span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">=</span> <span class="n">mousey</span>
<span class="n">drawArena</span><span class="p">()</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle1</span><span class="p">)</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle2</span><span class="p">)</span>
<span class="n">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">)</span>
<span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">moveBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">)</span>
<span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="n">checkEdgeCollision</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">)</span>
<span class="n">score</span> <span class="o" style="color: #666666;">=</span> <span class="n">checkPointScored</span><span class="p">(</span><span class="n">paddle1</span><span class="p">,</span> <span class="n">ball</span><span class="p">,</span> <span class="n">score</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">)</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">*</span> <span class="n">checkHitBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">paddle1</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">)</span>
<span class="n">paddle2</span> <span class="o" style="color: #666666;">=</span> <span class="n">artificialIntelligence</span> <span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">)</span>
<span class="n">displayScore</span><span class="p">(</span><span class="n">score</span><span class="p">)</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span>
<span class="n">FPSCLOCK</span><span class="o" style="color: #666666;">.</span><span class="n">tick</span><span class="p">(</span><span class="n">FPS</span><span class="p">)</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">__name__</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #ba2121;">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span></pre>
<br />
Most importantly don't be daunted! All will be revealed throughout this tutorial.<br />
<br />
<u><b>Stage 1 - Create a blank screen</b></u><br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: green; font-weight: bold;">import</span> <span class="nn" style="color: blue; font-weight: bold;">pygame</span><span class="o" style="color: #666666;">,</span> <span class="nn" style="color: blue; font-weight: bold;">sys</span>
<span class="kn" style="color: green; font-weight: bold;">from</span> <span class="nn" style="color: blue; font-weight: bold;">pygame.locals</span> <span class="kn" style="color: green; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="c" style="color: #408080; font-style: italic;"># Number of frames per second</span>
<span class="c" style="color: #408080; font-style: italic;"># Change this value to speed up or slow down your game</span>
<span class="n">FPS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">200</span>
<span class="c" style="color: #408080; font-style: italic;">#Global Variables to be used through our program</span>
<span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">400</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">300</span>
<span class="c" style="color: #408080; font-style: italic;">#Main function</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">main</span><span class="p">():</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">init</span><span class="p">()</span>
<span class="k" style="color: green; font-weight: bold;">global</span> <span class="n">DISPLAYSURF</span>
<span class="n">FPSCLOCK</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">time</span><span class="o" style="color: #666666;">.</span><span class="n">Clock</span><span class="p">()</span>
<span class="n">DISPLAYSURF</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_mode</span><span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_caption</span><span class="p">(</span><span class="s" style="color: #ba2121;">'Pong'</span><span class="p">)</span>
<span class="k" style="color: green; font-weight: bold;">while</span> <span class="bp" style="color: green;">True</span><span class="p">:</span> <span class="c" style="color: #408080; font-style: italic;">#main game loop</span>
<span class="k" style="color: green; font-weight: bold;">for</span> <span class="n">event</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">in</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">():</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">QUIT</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">quit</span><span class="p">()</span>
<span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span>
<span class="n">FPSCLOCK</span><span class="o" style="color: #666666;">.</span><span class="n">tick</span><span class="p">(</span><span class="n">FPS</span><span class="p">)</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">__name__</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #ba2121;">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span></pre>
<br />
Ok so where do we start? Well when programming in Pygame I always start with creating a blank screen.<br />
<br />
The first thing we need to do is to import the pygame libraries into our program so we have access to them.<br />
We are also importing the sys libraries which we will use later in this section to exit our game.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: green; font-weight: bold;">import</span> <span class="nn" style="color: blue; font-weight: bold;">pygame</span><span class="o" style="color: #666666;">,</span> <span class="nn" style="color: blue; font-weight: bold;">sys</span>
<span class="kn" style="color: green; font-weight: bold;">from</span> <span class="nn" style="color: blue; font-weight: bold;">pygame.locals</span> <span class="kn" style="color: green; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span></pre>
<br />
We will then set a global variable which will control the speed of the program. We do this by varying the number of Frame Per Second or FPS for short. For now we will set this to 200, but can vary this later.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #408080; font-style: italic;"># Number of frames per second</span>
<span class="c" style="color: #408080; font-style: italic;"># Change this value to speed up or slow down your game</span>
<span class="n">FPS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">200</span></pre>
<br />
Remember any line which starts with a # is not seen by the program when it is running. We use this to allow us to write notes about our code. You will see I do this a lot throughout this program. Comments are very useful when coming back to read your code at a later date.<br />
<br />
We also need some global variables for our window size. It is much easier when reading your program at a later date to remember what WINDOWHEIGHT means rather than a value such as 400 spread throughout your program. We will be able to call these variables at any time during our program.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #408080; font-style: italic;">#Global Variables to be used through our program</span>
<span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">400</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">300</span></pre>
<br />
Now we get into writing the main function of the program.<br />
<br />
As with any function we have to define the function before calling it.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">main</span><span class="p">():</span></pre>
<br />
The next line is needed to initialise pygame.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">init</span><span class="p">()</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
Pygame works by drawing onto surfaces. This next line creates the main surface we will use throughout our program. We have made it a global variable so we can access it later. Why did we have to use the word global on this variable and not on the previous variables? Well adding global allows us to modify the value later on. We will be changing our surface, so it's important we can modify it when we need to.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">global</span> <span class="n">DISPLAYSURF</span></pre>
<br />
The next line relates to the fact we want to set the frame rate ourselves, rather than allowing the program to run as fast as it wants.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">FPSCLOCK</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">time</span><span class="o" style="color: #666666;">.</span><span class="n">Clock</span><span class="p">()</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
Now we assign some information to our surface, which sets the display width and height.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">DISPLAYSURF</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_mode</span><span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span> </pre>
<br />
We set the height and the width to 400 and 300 respectively using the variables we created earlier. Notice how reading WINDOWHEIGHT and WINDOWWIDTH makes it a lot easier to understand what this line means rather than reading 400,300?<br />
<br />
Next we set the title of our window. You can put anything you want here, but I am going to call my window 'Pong'<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_caption</span><span class="p">(</span><span class="s" style="color: #ba2121;">'Pong'</span><span class="p">)</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
Now we get into the business end of our program with<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">while</span> <span class="bp" style="color: green;">True</span><span class="p">:</span> <span class="c" style="color: #408080; font-style: italic;">#main game loop</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
This is an eternal loop that will keep running until the game is quit.<br />
<br />
The first thing we should do is ensure we can quit! This is achieved during the next four lines of code.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">for</span> <span class="n">event</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">in</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">():</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">QUIT</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">quit</span><span class="p">()</span>
<span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
For now we are only creating a blank screen so our program is not going to do anything. This will of course change later.<br />
<br />
Therefore we can just ask the screen to update.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
We need the next line to tell our program to set the Frames Per Second (FPS) rate to use the FPS variable we defined earlier.<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">FPSCLOCK</span><span class="o" style="color: #666666;">.</span><span class="n">tick</span><span class="p">(</span><span class="n">FPS</span><span class="p">)</span></pre>
<br />
That is the end of our main function.<br />
<br />
There are a couple of lines we need to type in to call our main function.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">__name__</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #ba2121;">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
You should now save your game and press F5. Hopefully you see a window similar to this?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiI2gSP6Mq7WF0Yh5SKWqkQ0syg29PtnJs4uQVfZKuXU6J9-geIqA9M9gnzX_6Fz3lpprvWbKxNbRs9eAxsqTmx_8ERPyNZVko9Xr7QZibwdTO9yT4rmS1HCPHyvz-KKjthh9paQLOKPyk/s1600/pong-stage1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="263" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiI2gSP6Mq7WF0Yh5SKWqkQ0syg29PtnJs4uQVfZKuXU6J9-geIqA9M9gnzX_6Fz3lpprvWbKxNbRs9eAxsqTmx_8ERPyNZVko9Xr7QZibwdTO9yT4rmS1HCPHyvz-KKjthh9paQLOKPyk/s1600/pong-stage1.png" width="320" /></a></div>
<br />
<br />
Remember to save your work often as you go through the program. It's not much fun typing the same thing in twice!<br />
<br />
<b><u>Stage 2 - Draw the Arena, the paddles and the ball.</u></b><br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: green; font-weight: bold;">import</span> <span class="nn" style="color: blue; font-weight: bold;">pygame</span><span class="o" style="color: #666666;">,</span> <span class="nn" style="color: blue; font-weight: bold;">sys</span>
<span class="kn" style="color: green; font-weight: bold;">from</span> <span class="nn" style="color: blue; font-weight: bold;">pygame.locals</span> <span class="kn" style="color: green; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="c" style="color: #408080; font-style: italic;"># Number of frames per second</span>
<span class="c" style="color: #408080; font-style: italic;"># Change this value to speed up or slow down your game</span>
<span class="n">FPS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">200</span>
<span class="c" style="color: #408080; font-style: italic;">#Global Variables to be used through our program</span>
<span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">400</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">300</span>
<span class="n">LINETHICKNESS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">10</span>
<span class="n">PADDLESIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">50</span>
<span class="n">PADDLEOFFSET</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">20</span>
<span class="c" style="color: #408080; font-style: italic;"># Set up the colours</span>
<span class="n">BLACK</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #666666;">0</span> <span class="p">,</span><span class="mi" style="color: #666666;">0</span> <span class="p">,</span><span class="mi" style="color: #666666;">0</span> <span class="p">)</span>
<span class="n">WHITE</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #666666;">255</span><span class="p">,</span><span class="mi" style="color: #666666;">255</span><span class="p">,</span><span class="mi" style="color: #666666;">255</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the arena the game will be played in. </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawArena</span><span class="p">():</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">((</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">))</span>
<span class="c" style="color: #408080; font-style: italic;">#Draw outline of arena</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">),(</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">)),</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #666666;">2</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draw centre line</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">),</span><span class="mi" style="color: #666666;">0</span><span class="p">),((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">),</span><span class="n">WINDOWHEIGHT</span><span class="p">),</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">4</span><span class="p">))</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the paddle</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawPaddle</span><span class="p">(</span><span class="n">paddle</span><span class="p">):</span>
<span class="c" style="color: #408080; font-style: italic;">#Stops paddle moving too low</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span>
<span class="c" style="color: #408080; font-style: italic;">#Stops paddle moving too high</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">=</span> <span class="n">LINETHICKNESS</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws paddle</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">paddle</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#draws the ball</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">):</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">ball</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Main function</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">main</span><span class="p">():</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">init</span><span class="p">()</span>
<span class="k" style="color: green; font-weight: bold;">global</span> <span class="n">DISPLAYSURF</span>
<span class="n">FPSCLOCK</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">time</span><span class="o" style="color: #666666;">.</span><span class="n">Clock</span><span class="p">()</span>
<span class="n">DISPLAYSURF</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_mode</span><span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_caption</span><span class="p">(</span><span class="s" style="color: #ba2121;">'Pong'</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Initiate variable and set starting positions</span>
<span class="c" style="color: #408080; font-style: italic;">#any future changes made within rectangles</span>
<span class="n">ballX</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">ballY</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">playerOnePosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">playerTwoPosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="c" style="color: #408080; font-style: italic;">#Creates Rectangles for ball and paddles.</span>
<span class="n">paddle1</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">PADDLEOFFSET</span><span class="p">,</span><span class="n">playerOnePosition</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span><span class="n">PADDLESIZE</span><span class="p">)</span>
<span class="n">paddle2</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLEOFFSET</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">,</span> <span class="n">playerTwoPosition</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span><span class="n">PADDLESIZE</span><span class="p">)</span>
<span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">ballX</span><span class="p">,</span> <span class="n">ballY</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the starting position of the Arena</span>
<span class="n">drawArena</span><span class="p">()</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle1</span><span class="p">)</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle2</span><span class="p">)</span>
<span class="n">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">)</span>
<span class="k" style="color: green; font-weight: bold;">while</span> <span class="bp" style="color: green;">True</span><span class="p">:</span> <span class="c" style="color: #408080; font-style: italic;">#main game loop</span>
<span class="k" style="color: green; font-weight: bold;">for</span> <span class="n">event</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">in</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">():</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">QUIT</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">quit</span><span class="p">()</span>
<span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span>
<span class="n">drawArena</span><span class="p">()</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle1</span><span class="p">)</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle2</span><span class="p">)</span>
<span class="n">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">)</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span>
<span class="n">FPSCLOCK</span><span class="o" style="color: #666666;">.</span><span class="n">tick</span><span class="p">(</span><span class="n">FPS</span><span class="p">)</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">__name__</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #ba2121;">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span></pre>
<br />
Stage 1 was mainly some grunt work to write the bare minimum to get our game to work. The fun starts now. :-)<br />
<br />
In stage 2 we will be drawing our arena, the paddles and the ball.<br />
<br />
Below the other global variables defining the height and the width we will add a few more variables. Keeping these all grouped together makes it easier to read the code again at a later date.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">LINETHICKNESS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">10</span>
<span class="n">PADDLESIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">50</span>
<span class="n">PADDLEOFFSET</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">20</span></pre>
<br />
Again it is easier to read our code if we refer to LINETHICKNESS rather than 10 throughout our code.<br />
<br />
LINETHICKNESS will be used to determine the thickness of the lines throughout our program.<br />
PADDLESIZE is the length of the paddle.<br />
PADDLEOFFSET is the distance the paddle is from the arena edges.<br />
<br />
You can play around with all these variables later and see what happens.<br />
<br />
I also know that I will need my screen to have black and white elements.<br />
<br />
For ease I have set up some variables for the colours. The three values refer to the amount of Red, Green or Blue (RGB) in the colour.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #408080; font-style: italic;"># Set up the colours</span>
<span class="n">BLACK</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #666666;">0</span> <span class="p">,</span><span class="mi" style="color: #666666;">0</span> <span class="p">,</span><span class="mi" style="color: #666666;">0</span> <span class="p">)</span>
<span class="n">WHITE</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #666666;">255</span><span class="p">,</span><span class="mi" style="color: #666666;">255</span><span class="p">,</span><span class="mi" style="color: #666666;">255</span><span class="p">)</span></pre>
<br />
Lets jump back into our main function.<br />
<br />
We know that at some point we will expect our ball to move around the screen i.e. that it will move in X and Y. Our paddles however will move up and down i.e only move in Y.<br />
<br />
As a starting point we shall place the ball and the paddles in their central position.<br />
<br />
We will be defining our ball and paddles using rectangles. These will be defined by stating the top left co-ordinate of each rectangle and then the length and width of each.<br />
<br />
Let us create some variables for the ball and each paddle, and assign them values that will position then in their central positions.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #408080; font-style: italic;">#Initiate variable and set starting positions</span>
<span class="c" style="color: #408080; font-style: italic;">#any future changes made within rectangles</span>
<span class="n">ballX</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">ballY</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">playerOnePosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">playerTwoPosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
So if we want to place the ball in the centre, why not use WINDOWWIDTH / 2? Well that would place the top of the ball in the centre of the screen and not the centre of the ball. We need to reduce the position by half the ball size, which is half of the LINETHICKNESS.<br />
<br />
You can see we do the same for the paddle positions. This time I have shown the subtraction before dividing the whole value by two.<br />
<br />
Now we have our starting co-ordinates, let us create a rectangle for the ball and the paddles.<br />
<br />
The format for creating a rectangle is as follows.<br />
<br />
pygame.Rect(X co-ordinate, Y co-ordinate, Width of Rectangle, Length of Rectangle)<br />
<br />
As we have just defined all this information we can easily create the three rectangles,<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #408080; font-style: italic;">#Creates Rectangles for ball and paddles.</span>
<span class="n">paddle1</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">PADDLEOFFSET</span><span class="p">,</span><span class="n">playerOnePosition</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span><span class="n">PADDLESIZE</span><span class="p">)</span>
<span class="n">paddle2</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLEOFFSET</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">,</span> <span class="n">playerTwoPosition</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span><span class="n">PADDLESIZE</span><span class="p">)</span>
<span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">ballX</span><span class="p">,</span> <span class="n">ballY</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">)</span></pre>
<br />
For paddle 1 we use an X co-ordinate of PADDLEOFFSET which is defining the distance from the left hand side. Paddle 2 needs a little more work as this is on the right hand side.<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
The X co-ordinate for paddle 2 needs to be the width of the window (WINDOWWIDTH) minus the paddle offset (PADDLEOFFSET). However this would take us to the right hand side of the paddle, so we also need to minus off the thickness of the paddle (LINETHICKNESS). Therefore the X co-ordinate of paddle 2 would be WINDOWWIDTH - PADDLEOFFSET - LINETHICKNESS<br />
<br />
While we have defined the starting positions, and then the required rectangles, we have not actually drawn anything yet. To make it easier lets create a separate function to draw the arena, the two paddles and the ball.<br />
<br />
The code to call these functions is positioned directly below the rectangles we have created, and will set up our starting screen.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #408080; font-style: italic;">#Draws the starting position of the Arena</span>
<span class="n">drawArena</span><span class="p">()</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle1</span><span class="p">)</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle2</span><span class="p">)</span>
<span class="n">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">)</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
You will see that for the two players and the ball we pass the appropriate rectangle into the function, for the arena we don't pass anything into that function. The reason is as we move the paddles and the ball we will be updating the rectangle position to reflect the new position of these items. The arena remains the same throughout the game so the arena function will always draw the same thing regardless of where the ball and the paddles are.<br />
<br />
As the game progresses we will be moving the ball and the paddles around, so we should update the screen every tick or FPS.<br />
<br />
To do this we will call the same functions but this time within our while loop. This will ensure our game is updated so many times per second to match out FPS rate.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">drawArena</span><span class="p">()</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle1</span><span class="p">)</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle2</span><span class="p">)</span>
<span class="n">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">)</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<br />
Ok, we should now write these four functions.<br />
<br />
Starting with drawArena()<br />
<br />
Directly below where we defined the two colours type the following function. I will show you the whole function, then we will look at it line by line.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #408080; font-style: italic;">#Draws the arena the game will be played in. </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawArena</span><span class="p">():</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">((</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">))</span>
<span class="c" style="color: #408080; font-style: italic;">#Draw outline of arena</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">),(</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">)),</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #666666;">2</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draw centre line</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">),</span><span class="mi" style="color: #666666;">0</span><span class="p">),((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">),</span><span class="n">WINDOWHEIGHT</span><span class="p">),</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">4</span><span class="p">))</span></pre>
<br />
The first line defines the function name, and the fact the brackets are empty shows we are passing nothing into the function.<br />
<br />
Firstly we fill the screen background so it is all white.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">((</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">))</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
Now we want to draw a border all around the arena. We can do this as a rectangle, but rather than filling the rectangle as we did with the paddles and the ball we will make it hollow. This requires us to add an extra parameter which defines the thickness of the line.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #408080; font-style: italic;">#Draw outline of arena</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">),(</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">)),</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #666666;">2</span><span class="p">)</span></pre>
<br />
Let us analyse this line a little more.<br />
<br />
The DISPLAYSURF tells the program which surface we want to draw onto. In our case we will use DISPLAYSURF.<br />
WHITE tells us what colour the rectangle should be.<br />
((0,0),(WINDOWWIDTH,WINDOWHEIGHT)) defines a rectangle. (0,0) are the (left, top) co-ordinates, and (WINDOWWIDTH,WINDOWHEIGHT) are the width and height of the rectangle. Notice these are all within a set of brackets.<br />
<br />
Now we need to define the thickness of the line. Why have we used LINETHICKNESS * 2? Well our rectangle is around the edge of our window, and when we give it a thickness, half the line thickness is on the inside of the rectangle and half on the outside. Doubling the thickness means there is a total line of LINETHICKNESS on the inside of the rectangle, which you will see and an equal amount on the outside which you cannot see.<br />
<br />
Any good court should have a centre line, so we will draw one in our arena.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #408080; font-style: italic;">#Draw centre line</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">),</span><span class="mi" style="color: #666666;">0</span><span class="p">),((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">),</span><span class="n">WINDOWHEIGHT</span><span class="p">),</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">4</span><span class="p">))</span></pre>
<br />
This is very similar syntax to the rectangle but ((WINDOWWIDTH/2),0) are the starting (x,y) co-ordinates of the line and ((WINDOWWIDTH/2),WINDOWHEIGHT) are the end co-ordinates.<br />
We only want this to be a thin line so we use LINETHICKNESS / 4 to indicate its width.<br />
<br />
There we go that is all that is needed to draw the arena, so lets move swiftly onwards.<br />
<br />
We will create a function to draw the paddle. Now as we know we will want to draw a paddle for Paddle1 and Paddle2, we should be able to use the same function for both.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #408080; font-style: italic;">#Draws the paddle</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawPaddle</span><span class="p">(</span><span class="n">paddle</span><span class="p">):</span>
<span class="c" style="color: #408080; font-style: italic;">#Stops paddle moving too low</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span>
<span class="c" style="color: #408080; font-style: italic;">#Stops paddle moving too high</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">=</span> <span class="n">LINETHICKNESS</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws paddle</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">paddle</span><span class="p">)</span></pre>
<br />
Again the first line defines the function name and tells us we are accepting paddle as a parameter into the function. Now when we called the function earlier, one time we passed paddle1 into the function, and the second time paddle2. Well to help re-use code whatever we pass into this function will be called paddle. This means we can pass both paddle1 and paddle2 into it and it will refer to them as just paddle. This saves us having to write the same function twice, once for paddle1 and once for paddle2.<br />
<br />
Now I want to make sure that the paddle will stay within the arena. If it tries to move out of the bottom of the arena we limit it to its lowest point, then do something similar at the top.<br />
<br />
As paddle is a rectangle we can isolate the values that make up the rectangle, such as x and y. However pygame gives us more control than that so we can access the top, the bottom, left or right of the rectangle. In fact there are loads of options all listed on the pygame.rect page. If you would like to explore these yourself have a look at this link.<br />
<br />
<div style="text-align: center;">
<a href="http://www.pygame.org/docs/ref/rect.html">http://www.pygame.org/docs/ref/rect.html</a></div>
<br />
To ensure the paddle doesn't move off the bottom of the arena, it is easier if we look at the bottom of the paddle. This is done with paddle.bottom.<br />
<br />
We don't want our paddle bottom to move beyond the arena walls. The bottom arena wall is the height of the window minus the thickness of the wall. Our code therefore looks like this.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #408080; font-style: italic;">#Stops paddle moving too low</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span></pre>
<br />
We simply say if it moves too far, make it equal to the furthest point we want it to go to.<br />
<br />
The same is done to stop it moving too high. However this time we look at the top of the paddle using paddle.top<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #408080; font-style: italic;">#Stops paddle moving too high</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">=</span> <span class="n">LINETHICKNESS</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
Now we draw our rectangle<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #408080; font-style: italic;">#Draws paddle</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">paddle</span><span class="p">)</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
This is exactly the same as when we drew the rectangle for the arena. However instead of defining the rectangle inside the brackets, we use our predefined rectangle - paddle. Nice and easy.<br />
<br />
Finally we will write the function to draw the ball.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #408080; font-style: italic;">#draws the ball</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">):</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">ball</span><span class="p">)</span></pre>
<br />
We name the function drawBall and show it will accept ball.<br />
Then as we have done with the paddles we simply draw the ball. Very simple.<br />
<br />
Saving and running your program should show the arena with 2 paddles and a ball.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUkva16C3RWjTEztKUfrHPiVUhcqGk8CaiU286vND17xBZT82-NE9fMnaG1rdrAdy_8Fgu26cZmh0rlHhpUrthMcFQrNDs9y_PIvhtGqTBPYc4Xo3OxgQN2G4nKYZ33gDP-reXLcJqRyk/s1600/pong-stage2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUkva16C3RWjTEztKUfrHPiVUhcqGk8CaiU286vND17xBZT82-NE9fMnaG1rdrAdy_8Fgu26cZmh0rlHhpUrthMcFQrNDs9y_PIvhtGqTBPYc4Xo3OxgQN2G4nKYZ33gDP-reXLcJqRyk/s1600/pong-stage2.png" width="320" /></a></div>
<br />
<br />
<b><u>Stage 3 - Move the ball around. </u></b><br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: green; font-weight: bold;">import</span> <span class="nn" style="color: blue; font-weight: bold;">pygame</span><span class="o" style="color: #666666;">,</span> <span class="nn" style="color: blue; font-weight: bold;">sys</span>
<span class="kn" style="color: green; font-weight: bold;">from</span> <span class="nn" style="color: blue; font-weight: bold;">pygame.locals</span> <span class="kn" style="color: green; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="c" style="color: #408080; font-style: italic;"># Number of frames per second</span>
<span class="c" style="color: #408080; font-style: italic;"># Change this value to speed up or slow down your game</span>
<span class="n">FPS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">200</span>
<span class="c" style="color: #408080; font-style: italic;">#Global Variables to be used through our program</span>
<span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">400</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">300</span>
<span class="n">LINETHICKNESS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">10</span>
<span class="n">PADDLESIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">50</span>
<span class="n">PADDLEOFFSET</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">20</span>
<span class="c" style="color: #408080; font-style: italic;"># Set up the colours</span>
<span class="n">BLACK</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #666666;">0</span> <span class="p">,</span><span class="mi" style="color: #666666;">0</span> <span class="p">,</span><span class="mi" style="color: #666666;">0</span> <span class="p">)</span>
<span class="n">WHITE</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #666666;">255</span><span class="p">,</span><span class="mi" style="color: #666666;">255</span><span class="p">,</span><span class="mi" style="color: #666666;">255</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the arena the game will be played in. </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawArena</span><span class="p">():</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">((</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">))</span>
<span class="c" style="color: #408080; font-style: italic;">#Draw outline of arena</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">),(</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">)),</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #666666;">2</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draw centre line</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">),</span><span class="mi" style="color: #666666;">0</span><span class="p">),((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">),</span><span class="n">WINDOWHEIGHT</span><span class="p">),</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">4</span><span class="p">))</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the paddle</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawPaddle</span><span class="p">(</span><span class="n">paddle</span><span class="p">):</span>
<span class="c" style="color: #408080; font-style: italic;">#Stops paddle moving too low</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span>
<span class="c" style="color: #408080; font-style: italic;">#Stops paddle moving too high</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">=</span> <span class="n">LINETHICKNESS</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws paddle</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">paddle</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#draws the ball</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">):</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">ball</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#moves the ball returns new position</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">moveBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">):</span>
<span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">x</span> <span class="o" style="color: #666666;">+=</span> <span class="n">ballDirX</span>
<span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="n">ballDirY</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">ball</span>
<span class="c" style="color: #408080; font-style: italic;">#Main function</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">main</span><span class="p">():</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">init</span><span class="p">()</span>
<span class="k" style="color: green; font-weight: bold;">global</span> <span class="n">DISPLAYSURF</span>
<span class="n">FPSCLOCK</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">time</span><span class="o" style="color: #666666;">.</span><span class="n">Clock</span><span class="p">()</span>
<span class="n">DISPLAYSURF</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_mode</span><span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_caption</span><span class="p">(</span><span class="s" style="color: #ba2121;">'Pong'</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Initiate variable and set starting positions</span>
<span class="c" style="color: #408080; font-style: italic;">#any future changes made within rectangles</span>
<span class="n">ballX</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">ballY</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">playerOnePosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">playerTwoPosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="c" style="color: #408080; font-style: italic;">#Keeps track of ball direction</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="c" style="color: #408080; font-style: italic;">## -1 = left 1 = right</span>
<span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="c" style="color: #408080; font-style: italic;">## -1 = up 1 = down</span>
<span class="c" style="color: #408080; font-style: italic;">#Creates Rectangles for ball and paddles.</span>
<span class="n">paddle1</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">PADDLEOFFSET</span><span class="p">,</span><span class="n">playerOnePosition</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span><span class="n">PADDLESIZE</span><span class="p">)</span>
<span class="n">paddle2</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLEOFFSET</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">,</span> <span class="n">playerTwoPosition</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span><span class="n">PADDLESIZE</span><span class="p">)</span>
<span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">ballX</span><span class="p">,</span> <span class="n">ballY</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the starting position of the Arena</span>
<span class="n">drawArena</span><span class="p">()</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle1</span><span class="p">)</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle2</span><span class="p">)</span>
<span class="n">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">)</span>
<span class="k" style="color: green; font-weight: bold;">while</span> <span class="bp" style="color: green;">True</span><span class="p">:</span> <span class="c" style="color: #408080; font-style: italic;">#main game loop</span>
<span class="k" style="color: green; font-weight: bold;">for</span> <span class="n">event</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">in</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">():</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">QUIT</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">quit</span><span class="p">()</span>
<span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span>
<span class="n">drawArena</span><span class="p">()</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle1</span><span class="p">)</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle2</span><span class="p">)</span>
<span class="n">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">)</span>
<span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">moveBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">)</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span>
<span class="n">FPSCLOCK</span><span class="o" style="color: #666666;">.</span><span class="n">tick</span><span class="p">(</span><span class="n">FPS</span><span class="p">)</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">__name__</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #ba2121;">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span></pre>
<br />
While we can see our game is taking shape, there is not much actually happening. We will change this now by moving the ball around. First lets determine which way the ball is moving.<br />
<br />
My method of doing this is to create two variables. One for the direction of the ball in X, and one in Y. This allows us to control the ball in each axis independently. Lets create these variables below our initial ball and player positions.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #408080; font-style: italic;">#Keeps track of ball direction</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="c" style="color: #408080; font-style: italic;">## -1 = left 1 = right</span>
<span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="c" style="color: #408080; font-style: italic;">## -1 = up 1 = down</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
Lets say if the ball is moving left, we will make ballDirX = -1, and if it is moving right we will make it 1<br />
Similarly if it is moving up we will make ballDirY = -1 and down ballDirY = 1.<br />
<br />
Every FPS we will want to move the ball. Therefore we will write a function which will move the ball by updating the co-ordinates stored in the ball rectangle. We will need to pass into the function the value for ball, and the X and Y directions, ballDirX and ballDirY. Under where we called the drawBall() function in our main loop add the following line to call the moveBall function.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">moveBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">)</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
Whatever is output from our moveBall function will become the new value of ball.<br />
<br />
Outside the main loop with the other functions lets create the function moveBall below the drawBall function.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #408080; font-style: italic;">#moves the ball returns new position</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">moveBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">):</span>
<span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">x</span> <span class="o" style="color: #666666;">+=</span> <span class="n">ballDirX</span>
<span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="n">ballDirY</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">ball</span></pre>
<br />
After naming the function listing the parameters being passed into it we simply add to the x value of ball the value from ballDirX.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">x</span> <span class="o" style="color: #666666;">+=</span> <span class="n">ballDirX</span></pre>
<br />
If you are confused about the meaning of += remember a += b is equal to a = a + b.<br />
<br />
This means if the ball should be moving left, we add -1 onto the co-ordinates of the ball, which moves the ball left. If ballDirX is 1, ball.x would increase by 1, moving it to the right.<br />
<br />
We then do a similar thing for ball.y<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="n">ballDirY</span></pre>
<br />
Finally we return the modified ball back into our main function.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">ball</span></pre>
<br />
Time to save your file and test out step 3 moving the ball.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7rdBUUzJVaP-MHe7RhcwarMF6spFJ6yGRx6hc8RrFVMmksdSFh0o6JE0UmZySzR9W6xODOKErJpzOOGX9ih_dMKTqh70JaT4Y72SXwI5gGHb6E2qo7PeGY8AUyOfH21uCMRbelwoFft8/s1600/pong-stage3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7rdBUUzJVaP-MHe7RhcwarMF6spFJ6yGRx6hc8RrFVMmksdSFh0o6JE0UmZySzR9W6xODOKErJpzOOGX9ih_dMKTqh70JaT4Y72SXwI5gGHb6E2qo7PeGY8AUyOfH21uCMRbelwoFft8/s1600/pong-stage3.png" width="320" /></a></div>
<br />
<br />
<u><b>Step 4 - Check collision with all edges</b></u><br />
<br />
<pre style="background-color: #f0f0f0; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">pygame</span><span class="o" style="color: #666666;">,</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">sys</span>
<span class="kn" style="color: #007020; font-weight: bold;">from</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">pygame.locals</span> <span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># Number of frames per second</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># Change this value to speed up or slow down your game</span>
<span class="n">FPS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">200</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Global Variables to be used through our program</span>
<span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">400</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">300</span>
<span class="n">LINETHICKNESS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">10</span>
<span class="n">PADDLESIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">50</span>
<span class="n">PADDLEOFFSET</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">20</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># Set up the colours</span>
<span class="n">BLACK</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span> <span class="p">,</span><span class="mi" style="color: #40a070;">0</span> <span class="p">,</span><span class="mi" style="color: #40a070;">0</span> <span class="p">)</span>
<span class="n">WHITE</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Draws the arena the game will be played in. </span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">drawArena</span><span class="p">():</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">((</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">))</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Draw outline of arena</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">),(</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">)),</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #40a070;">2</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Draw centre line</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">2</span><span class="p">),</span><span class="mi" style="color: #40a070;">0</span><span class="p">),((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">2</span><span class="p">),</span><span class="n">WINDOWHEIGHT</span><span class="p">),</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">4</span><span class="p">))</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Draws the paddle</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">drawPaddle</span><span class="p">(</span><span class="n">paddle</span><span class="p">):</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Stops paddle moving too low</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Stops paddle moving too high</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">=</span> <span class="n">LINETHICKNESS</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Draws paddle</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">paddle</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#draws the ball</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">):</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">ball</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#moves the ball returns new position</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">moveBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">):</span>
<span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">x</span> <span class="o" style="color: #666666;">+=</span> <span class="n">ballDirX</span>
<span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="n">ballDirY</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">ball</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Checks for a collision with a wall, and 'bounces' ball off it.</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Returns new direction</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">checkEdgeCollision</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="p">)</span> <span class="ow" style="color: #007020; font-weight: bold;">or</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">):</span>
<span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirY</span> <span class="o" style="color: #666666;">*</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="p">)</span> <span class="ow" style="color: #007020; font-weight: bold;">or</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">):</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">*</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Main function</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">main</span><span class="p">():</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">init</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">global</span> <span class="n">DISPLAYSURF</span>
<span class="n">FPSCLOCK</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">time</span><span class="o" style="color: #666666;">.</span><span class="n">Clock</span><span class="p">()</span>
<span class="n">DISPLAYSURF</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_mode</span><span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_caption</span><span class="p">(</span><span class="s" style="color: #4070a0;">'Pong'</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Initiate variable and set starting positions</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#any future changes made within rectangles</span>
<span class="n">ballX</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">2</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">2</span>
<span class="n">ballY</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">2</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">2</span>
<span class="n">playerOnePosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">2</span>
<span class="n">playerTwoPosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">2</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Keeps track of ball direction</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span> <span class="c" style="color: #60a0b0; font-style: italic;">## -1 = left 1 = right</span>
<span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span> <span class="c" style="color: #60a0b0; font-style: italic;">## -1 = up 1 = down</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Creates Rectangles for ball and paddles.</span>
<span class="n">paddle1</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">PADDLEOFFSET</span><span class="p">,</span><span class="n">playerOnePosition</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span><span class="n">PADDLESIZE</span><span class="p">)</span>
<span class="n">paddle2</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLEOFFSET</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">,</span> <span class="n">playerTwoPosition</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span><span class="n">PADDLESIZE</span><span class="p">)</span>
<span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">ballX</span><span class="p">,</span> <span class="n">ballY</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Draws the starting position of the Arena</span>
<span class="n">drawArena</span><span class="p">()</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle1</span><span class="p">)</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle2</span><span class="p">)</span>
<span class="n">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">while</span> <span class="bp" style="color: #007020;">True</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;">#main game loop</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">event</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">QUIT</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">quit</span><span class="p">()</span>
<span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span>
<span class="n">drawArena</span><span class="p">()</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle1</span><span class="p">)</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle2</span><span class="p">)</span>
<span class="n">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">)</span>
<span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">moveBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">)</span>
<span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="n">checkEdgeCollision</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">)</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span>
<span class="n">FPSCLOCK</span><span class="o" style="color: #666666;">.</span><span class="n">tick</span><span class="p">(</span><span class="n">FPS</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">__name__</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span></pre>
<br />
So how is that moving the ball function working out for you? Well the ball certainly moves, but it disappears off the side of the arena, and keeps going!<br />
<br />
How will we deal with this? Well, if the ball hits one of the edges, we need to reverse the direction it is travelling in. If it hits the top or bottom edge we should reverse the ballDirY, and if it hits the left or right edge we should reverse ballDirX. We will do this in a function, but before that in our main game loop lets add a call to that function. So below ball = moveBall(ball, ballDirX, ballDirY) add the following line.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="n">checkEdgeCollision</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">)</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
So we are calling a function checkEdgeCollision. The function will need to know the ball position and the current direction in X and Y, therefore we pass those parameters into the function.<br />
<br />
Any collision will need to change ballDirX and ballDirY, so the output of the function will modify these as required.<br />
<br />
OK time to write the function.<br />
<br />
Outside of the main function underneath the moveBall function we will write our function called checkEdgeCollision<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #408080; font-style: italic;">#Checks for a collision with a wall, and 'bounces' ball off it.</span>
<span class="c" style="color: #408080; font-style: italic;">#Returns new direction</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">checkEdgeCollision</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">):</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="p">)</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">or</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">):</span>
<span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirY</span> <span class="o" style="color: #666666;">*</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="p">)</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">or</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">):</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">*</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span></pre>
<br />
So after naming the function we check to see if the top of the ball has hit the top of the arena, or the bottom of the ball has hit the bottom of the arena.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="p">)</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">or</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">):</span>
<span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirY</span> <span class="o" style="color: #666666;">*</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span></pre>
<br />
If that is the case we multiply our Y direction by -1.<br />
<br />
For those whose mathematics is not great,<br />
<br />
1 x -1 = -1<br />
-1 x -1 = 1<br />
<br />
Therefore if the direction was negative, it becomes positive and vice versa.<br />
<br />
We do the same thing for the left and right of the ball.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="p">)</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">or</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">):</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">*</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
and finally we return the X and Y directions, as our code is expecting us to.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
Wow that edge detection function was pretty easy huh?<br />
<br />
Again save and test your code. Do you see a ball bouncing around the screen?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh__zb6xERC0Liqfi9WKc-fUe5553w-u0yeKpeQZFIXuwtTe7uzSMTaHTNrrr3LeV6Zyg6h2KMRJbeRtdAKueXGvWiex_d6oZ_Insjy9iTz9t0z4y24nCRsYy0hJToffk_Vmiq5wQwrWBo/s1600/pong-stage4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh__zb6xERC0Liqfi9WKc-fUe5553w-u0yeKpeQZFIXuwtTe7uzSMTaHTNrrr3LeV6Zyg6h2KMRJbeRtdAKueXGvWiex_d6oZ_Insjy9iTz9t0z4y24nCRsYy0hJToffk_Vmiq5wQwrWBo/s1600/pong-stage4.png" width="320" /></a></div>
<br />
<br />
<b><u>Stage 5 - Move the players paddle.</u></b><br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: green; font-weight: bold;">import</span> <span class="nn" style="color: blue; font-weight: bold;">pygame</span><span class="o" style="color: #666666;">,</span> <span class="nn" style="color: blue; font-weight: bold;">sys</span>
<span class="kn" style="color: green; font-weight: bold;">from</span> <span class="nn" style="color: blue; font-weight: bold;">pygame.locals</span> <span class="kn" style="color: green; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="c" style="color: #408080; font-style: italic;"># Number of frames per second</span>
<span class="c" style="color: #408080; font-style: italic;"># Change this value to speed up or slow down your game</span>
<span class="n">FPS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">200</span>
<span class="c" style="color: #408080; font-style: italic;">#Global Variables to be used through our program</span>
<span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">400</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">300</span>
<span class="n">LINETHICKNESS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">10</span>
<span class="n">PADDLESIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">50</span>
<span class="n">PADDLEOFFSET</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">20</span>
<span class="c" style="color: #408080; font-style: italic;"># Set up the colours</span>
<span class="n">BLACK</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #666666;">0</span> <span class="p">,</span><span class="mi" style="color: #666666;">0</span> <span class="p">,</span><span class="mi" style="color: #666666;">0</span> <span class="p">)</span>
<span class="n">WHITE</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #666666;">255</span><span class="p">,</span><span class="mi" style="color: #666666;">255</span><span class="p">,</span><span class="mi" style="color: #666666;">255</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the arena the game will be played in. </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawArena</span><span class="p">():</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">((</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">))</span>
<span class="c" style="color: #408080; font-style: italic;">#Draw outline of arena</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">),(</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">)),</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #666666;">2</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draw centre line</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">),</span><span class="mi" style="color: #666666;">0</span><span class="p">),((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">),</span><span class="n">WINDOWHEIGHT</span><span class="p">),</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">4</span><span class="p">))</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the paddle</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawPaddle</span><span class="p">(</span><span class="n">paddle</span><span class="p">):</span>
<span class="c" style="color: #408080; font-style: italic;">#Stops paddle moving too low</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span>
<span class="c" style="color: #408080; font-style: italic;">#Stops paddle moving too high</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">=</span> <span class="n">LINETHICKNESS</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws paddle</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">paddle</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#draws the ball</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">):</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">ball</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#moves the ball returns new position</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">moveBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">):</span>
<span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">x</span> <span class="o" style="color: #666666;">+=</span> <span class="n">ballDirX</span>
<span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="n">ballDirY</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">ball</span>
<span class="c" style="color: #408080; font-style: italic;">#Checks for a collision with a wall, and 'bounces' ball off it.</span>
<span class="c" style="color: #408080; font-style: italic;">#Returns new direction</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">checkEdgeCollision</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">):</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="p">)</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">or</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">):</span>
<span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirY</span> <span class="o" style="color: #666666;">*</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="p">)</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">or</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">):</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">*</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span>
<span class="c" style="color: #408080; font-style: italic;">#Main function</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">main</span><span class="p">():</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">init</span><span class="p">()</span>
<span class="k" style="color: green; font-weight: bold;">global</span> <span class="n">DISPLAYSURF</span>
<span class="n">FPSCLOCK</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">time</span><span class="o" style="color: #666666;">.</span><span class="n">Clock</span><span class="p">()</span>
<span class="n">DISPLAYSURF</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_mode</span><span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_caption</span><span class="p">(</span><span class="s" style="color: #ba2121;">'Pong'</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Initiate variable and set starting positions</span>
<span class="c" style="color: #408080; font-style: italic;">#any future changes made within rectangles</span>
<span class="n">ballX</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">ballY</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">playerOnePosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">playerTwoPosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="c" style="color: #408080; font-style: italic;">#Keeps track of ball direction</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="c" style="color: #408080; font-style: italic;">## -1 = left 1 = right</span>
<span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="c" style="color: #408080; font-style: italic;">## -1 = up 1 = down</span>
<span class="c" style="color: #408080; font-style: italic;">#Creates Rectangles for ball and paddles.</span>
<span class="n">paddle1</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">PADDLEOFFSET</span><span class="p">,</span><span class="n">playerOnePosition</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span><span class="n">PADDLESIZE</span><span class="p">)</span>
<span class="n">paddle2</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLEOFFSET</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">,</span> <span class="n">playerTwoPosition</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span><span class="n">PADDLESIZE</span><span class="p">)</span>
<span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">ballX</span><span class="p">,</span> <span class="n">ballY</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the starting position of the Arena</span>
<span class="n">drawArena</span><span class="p">()</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle1</span><span class="p">)</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle2</span><span class="p">)</span>
<span class="n">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">)</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">mouse</span><span class="o" style="color: #666666;">.</span><span class="n">set_visible</span><span class="p">(</span><span class="mi" style="color: #666666;">0</span><span class="p">)</span> <span class="c" style="color: #408080; font-style: italic;"># make cursor invisible</span>
<span class="k" style="color: green; font-weight: bold;">while</span> <span class="bp" style="color: green;">True</span><span class="p">:</span> <span class="c" style="color: #408080; font-style: italic;">#main game loop</span>
<span class="k" style="color: green; font-weight: bold;">for</span> <span class="n">event</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">in</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">():</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">QUIT</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">quit</span><span class="p">()</span>
<span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span>
<span class="c" style="color: #408080; font-style: italic;"># mouse movement commands</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">MOUSEMOTION</span><span class="p">:</span>
<span class="n">mousex</span><span class="p">,</span> <span class="n">mousey</span> <span class="o" style="color: #666666;">=</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">pos</span>
<span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">=</span> <span class="n">mousey</span>
<span class="n">drawArena</span><span class="p">()</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle1</span><span class="p">)</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle2</span><span class="p">)</span>
<span class="n">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">)</span>
<span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">moveBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">)</span>
<span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="n">checkEdgeCollision</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">)</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span>
<span class="n">FPSCLOCK</span><span class="o" style="color: #666666;">.</span><span class="n">tick</span><span class="p">(</span><span class="n">FPS</span><span class="p">)</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">__name__</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #ba2121;">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span></pre>
<br />
While it is nice to see the ball moving so well, its a little frustrating we cannot hit it! I am sure we can resolve that fairly easily.<br />
<br />
Earlier on we created an event.type which was equal to quit. Well there are a few event types in Python and one of those is checking the motion of the mouse.<br />
<br />
Underneath sys.exit() which is the previous event type you programmed type the following.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #408080; font-style: italic;"># mouse movement commands</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">MOUSEMOTION</span><span class="p">:</span>
<span class="n">mousex</span><span class="p">,</span> <span class="n">mousey</span> <span class="o" style="color: #666666;">=</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">pos</span>
<span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">=</span> <span class="n">mousey</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
The first event checked for a QUIT and then exited the game. This was held within an 'if' statement. The second part you have just typed is an 'elif' statement which is checked if the 'if' statement was not true.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">MOUSEMOTION</span><span class="p">:</span></pre>
<br />
Else if (elif) the event type is mouse motion<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">mousex</span><span class="p">,</span> <span class="n">mousey</span> <span class="o" style="color: #666666;">=</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">pos</span></pre>
<br />
This gives the X and Y co-ordinates of the mouse position. Our game is not really interested in the X position, only the Y. We can therefore make the y position of paddle1 equal to the mousey position.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">=</span> <span class="n">mousey</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
Wow, Pygame really makes these things easy doesn't it?<br />
<br />
If you run your game you will see you have control over your paddle. However the fact you can see the mouse cursor is a little annoying, so lets turn that off.<br />
<br />
Just before your while True: loop in the main function type the following.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">mouse</span><span class="o" style="color: #666666;">.</span><span class="n">set_visible</span><span class="p">(</span><span class="mi" style="color: #666666;">0</span><span class="p">)</span> <span class="c" style="color: #408080; font-style: italic;"># make cursor invisible</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
This means you cannot see the cursor in your game.<br />
<br />
Again run your game and see if that has made it better.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDfkdZJ7l1YY94hRolrIoeud68qRYEMM1blZYS7XwMPtZTWHgK9mbXqCBjYh040utP_6aOb9a9FDs6buqidqwIA5mmL9FjtA-QEQW3aEmHUTYXQz3CA8D9WG5JC0COO5_4WRKfNWihHHg/s1600/pong-stage5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDfkdZJ7l1YY94hRolrIoeud68qRYEMM1blZYS7XwMPtZTWHgK9mbXqCBjYh040utP_6aOb9a9FDs6buqidqwIA5mmL9FjtA-QEQW3aEmHUTYXQz3CA8D9WG5JC0COO5_4WRKfNWihHHg/s1600/pong-stage5.png" width="320" /></a></div>
<br />
<br />
<b><u>Stage 6 - Move the computers paddle with 'Artificial Intelligence'</u></b><br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: green; font-weight: bold;">import</span> <span class="nn" style="color: blue; font-weight: bold;">pygame</span><span class="o" style="color: #666666;">,</span> <span class="nn" style="color: blue; font-weight: bold;">sys</span>
<span class="kn" style="color: green; font-weight: bold;">from</span> <span class="nn" style="color: blue; font-weight: bold;">pygame.locals</span> <span class="kn" style="color: green; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="c" style="color: #408080; font-style: italic;"># Number of frames per second</span>
<span class="c" style="color: #408080; font-style: italic;"># Change this value to speed up or slow down your game</span>
<span class="n">FPS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">200</span>
<span class="c" style="color: #408080; font-style: italic;">#Global Variables to be used through our program</span>
<span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">400</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">300</span>
<span class="n">LINETHICKNESS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">10</span>
<span class="n">PADDLESIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">50</span>
<span class="n">PADDLEOFFSET</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">20</span>
<span class="c" style="color: #408080; font-style: italic;"># Set up the colours</span>
<span class="n">BLACK</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #666666;">0</span> <span class="p">,</span><span class="mi" style="color: #666666;">0</span> <span class="p">,</span><span class="mi" style="color: #666666;">0</span> <span class="p">)</span>
<span class="n">WHITE</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #666666;">255</span><span class="p">,</span><span class="mi" style="color: #666666;">255</span><span class="p">,</span><span class="mi" style="color: #666666;">255</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the arena the game will be played in. </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawArena</span><span class="p">():</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">((</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">))</span>
<span class="c" style="color: #408080; font-style: italic;">#Draw outline of arena</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">),(</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">)),</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #666666;">2</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draw centre line</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">),</span><span class="mi" style="color: #666666;">0</span><span class="p">),((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">),</span><span class="n">WINDOWHEIGHT</span><span class="p">),</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">4</span><span class="p">))</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the paddle</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawPaddle</span><span class="p">(</span><span class="n">paddle</span><span class="p">):</span>
<span class="c" style="color: #408080; font-style: italic;">#Stops paddle moving too low</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span>
<span class="c" style="color: #408080; font-style: italic;">#Stops paddle moving too high</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">=</span> <span class="n">LINETHICKNESS</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws paddle</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">paddle</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#draws the ball</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">):</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">ball</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#moves the ball returns new position</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">moveBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">):</span>
<span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">x</span> <span class="o" style="color: #666666;">+=</span> <span class="n">ballDirX</span>
<span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="n">ballDirY</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">ball</span>
<span class="c" style="color: #408080; font-style: italic;">#Checks for a collision with a wall, and 'bounces' ball off it.</span>
<span class="c" style="color: #408080; font-style: italic;">#Returns new direction</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">checkEdgeCollision</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">):</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="p">)</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">or</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">):</span>
<span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirY</span> <span class="o" style="color: #666666;">*</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="p">)</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">or</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">):</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">*</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span>
<span class="c" style="color: #408080; font-style: italic;">#Artificial Intelligence of computer player </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">artificialIntelligence</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">):</span>
<span class="c" style="color: #408080; font-style: italic;">#If ball is moving away from paddle, center bat</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;"><</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">):</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;">></span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">):</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">-=</span> <span class="mi" style="color: #666666;">1</span>
<span class="c" style="color: #408080; font-style: italic;">#if ball moving towards bat, track its movement. </span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #666666;">1</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span><span class="p">:</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">-=</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">paddle2</span>
<span class="c" style="color: #408080; font-style: italic;">#Main function</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">main</span><span class="p">():</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">init</span><span class="p">()</span>
<span class="k" style="color: green; font-weight: bold;">global</span> <span class="n">DISPLAYSURF</span>
<span class="n">FPSCLOCK</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">time</span><span class="o" style="color: #666666;">.</span><span class="n">Clock</span><span class="p">()</span>
<span class="n">DISPLAYSURF</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_mode</span><span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_caption</span><span class="p">(</span><span class="s" style="color: #ba2121;">'Pong'</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Initiate variable and set starting positions</span>
<span class="c" style="color: #408080; font-style: italic;">#any future changes made within rectangles</span>
<span class="n">ballX</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">ballY</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">playerOnePosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">playerTwoPosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="c" style="color: #408080; font-style: italic;">#Keeps track of ball direction</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="c" style="color: #408080; font-style: italic;">## -1 = left 1 = right</span>
<span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="c" style="color: #408080; font-style: italic;">## -1 = up 1 = down</span>
<span class="c" style="color: #408080; font-style: italic;">#Creates Rectangles for ball and paddles.</span>
<span class="n">paddle1</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">PADDLEOFFSET</span><span class="p">,</span><span class="n">playerOnePosition</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span><span class="n">PADDLESIZE</span><span class="p">)</span>
<span class="n">paddle2</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLEOFFSET</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">,</span> <span class="n">playerTwoPosition</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span><span class="n">PADDLESIZE</span><span class="p">)</span>
<span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">ballX</span><span class="p">,</span> <span class="n">ballY</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the starting position of the Arena</span>
<span class="n">drawArena</span><span class="p">()</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle1</span><span class="p">)</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle2</span><span class="p">)</span>
<span class="n">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">)</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">mouse</span><span class="o" style="color: #666666;">.</span><span class="n">set_visible</span><span class="p">(</span><span class="mi" style="color: #666666;">0</span><span class="p">)</span> <span class="c" style="color: #408080; font-style: italic;"># make cursor invisible</span>
<span class="k" style="color: green; font-weight: bold;">while</span> <span class="bp" style="color: green;">True</span><span class="p">:</span> <span class="c" style="color: #408080; font-style: italic;">#main game loop</span>
<span class="k" style="color: green; font-weight: bold;">for</span> <span class="n">event</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">in</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">():</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">QUIT</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">quit</span><span class="p">()</span>
<span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span>
<span class="c" style="color: #408080; font-style: italic;"># mouse movement commands</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">MOUSEMOTION</span><span class="p">:</span>
<span class="n">mousex</span><span class="p">,</span> <span class="n">mousey</span> <span class="o" style="color: #666666;">=</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">pos</span>
<span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">=</span> <span class="n">mousey</span>
<span class="n">drawArena</span><span class="p">()</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle1</span><span class="p">)</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle2</span><span class="p">)</span>
<span class="n">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">)</span>
<span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">moveBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">)</span>
<span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="n">checkEdgeCollision</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">)</span>
<span class="n">paddle2</span> <span class="o" style="color: #666666;">=</span> <span class="n">artificialIntelligence</span> <span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">)</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span>
<span class="n">FPSCLOCK</span><span class="o" style="color: #666666;">.</span><span class="n">tick</span><span class="p">(</span><span class="n">FPS</span><span class="p">)</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">__name__</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #ba2121;">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span></pre>
<br />
While being able to move your paddle is all very good, it's not much fun if the computer doesn't move his paddle. Before allowing you to hit the ball lets add some 'artificial intelligence' into the computer.<br />
<br />
The computer is not really thinking for itself, so we are not programming Artificial Intelligence in the true sense of the word. It is just following a predetermined set of instructions.<br />
<br />
You can think of your own method of this if you like later. I am going to make the computer player play similar to how I play squash.<br />
<br />
<ul>
<li>Once I have hit the ball I move to the centre of the court.</li>
<li>When my opponent has hit the ball I start to follow the ball so I can hit it back.</li>
</ul>
<br />
Again we will do all the hard work in a function.<br />
<br />
That function will need to know:<br />
The position of the ball so it can follow it.<br />
The direction of the ball so it knows if it is moving away or towards the computers paddle.<br />
The position of the paddle so it can adjust its position depending on what the ball is doing.<br />
<br />
The output will be the position of the paddle.<br />
<br />
Therefore in our main loop lets create a call to a function called artificialIntelligence to suit our requirements.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">paddle2</span> <span class="o" style="color: #666666;">=</span> <span class="n">artificialIntelligence</span> <span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">)</span></pre>
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
Here is the function in its entirety. Have a read through and we will break it down in more detail.<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #408080; font-style: italic;">#Artificial Intelligence of computer player </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">artificialIntelligence</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">):</span>
<span class="c" style="color: #408080; font-style: italic;">#If ball is moving away from paddle, center bat</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;"><</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">):</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;">></span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">):</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">-=</span> <span class="mi" style="color: #666666;">1</span>
<span class="c" style="color: #408080; font-style: italic;">#if ball moving towards bat, track its movement. </span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #666666;">1</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span><span class="p">:</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">-=</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">paddle2</span></pre>
<br />
After naming the function with the correct parameters being passed into it we check to see if the ball is moving away from the paddle.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span><span class="p">:</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
If it is we do one of two things.<br />
<br />
If the center of the paddle in y is higher (remember the top of the screen is position 0) than the center of the screen, we move the paddle down by one.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;"><</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">):</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">1</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
Notice we use another of the great options when working with rectangles to find the center of the rectangle in y by using paddle2.centery<br />
<br />
If it is lower, we move it up by one.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;">></span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">):</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">-=</span> <span class="mi" style="color: #666666;">1</span></pre>
<br />
We have used less than and greater than. This means if the centery is equal to the WINDOWHEIGHT/2 it wont try to move and will sit stable in the central position.<br />
<br />
That covers if the ball is moving away from the bat. If it is moving towards the bat we said we would move the bat towards the ball.<br />
<br />
We first define the elif part of the loop to check if the ball is moving towards the paddle.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #408080; font-style: italic;">#if ball moving towards bat, track its movement. </span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #666666;">1</span><span class="p">:</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
In a similar manner to when the ball was moving away from the paddle we check to see the position of the paddle this time with respect to the ball. If it is higher than the ball we increase the paddle Y co-ordinate.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span><span class="p">:</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">1</span></pre>
<br />
Else, it must be lower so we decrease the paddle Y co-ordinate.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">-=</span><span class="mi" style="color: #666666;">1</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
Finally we return paddle2.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">paddle2</span></pre>
<br />
Right time to save and test your program.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyxGUn7CX18ao3iTaQwhvSQH5b7suK7sF_z-D7_q0SQC5NfKKRjkyuQ4l_xRCAoVV5GuDnNobiwew3FknT2WIvqAMJBz7llHyWXIbupZZgA-tUC_aCE8WtBEFnivufJQFn4tWuDX12O8s/s1600/pong-stage6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyxGUn7CX18ao3iTaQwhvSQH5b7suK7sF_z-D7_q0SQC5NfKKRjkyuQ4l_xRCAoVV5GuDnNobiwew3FknT2WIvqAMJBz7llHyWXIbupZZgA-tUC_aCE8WtBEFnivufJQFn4tWuDX12O8s/s1600/pong-stage6.png" width="320" /></a></div>
<br />
<br />
<b><u> Stage 7 - Collision with the paddle</u></b><br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: green; font-weight: bold;">import</span> <span class="nn" style="color: blue; font-weight: bold;">pygame</span><span class="o" style="color: #666666;">,</span> <span class="nn" style="color: blue; font-weight: bold;">sys</span>
<span class="kn" style="color: green; font-weight: bold;">from</span> <span class="nn" style="color: blue; font-weight: bold;">pygame.locals</span> <span class="kn" style="color: green; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="c" style="color: #408080; font-style: italic;"># Number of frames per second</span>
<span class="c" style="color: #408080; font-style: italic;"># Change this value to speed up or slow down your game</span>
<span class="n">FPS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">200</span>
<span class="c" style="color: #408080; font-style: italic;">#Global Variables to be used through our program</span>
<span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">400</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">300</span>
<span class="n">LINETHICKNESS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">10</span>
<span class="n">PADDLESIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">50</span>
<span class="n">PADDLEOFFSET</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">20</span>
<span class="c" style="color: #408080; font-style: italic;"># Set up the colours</span>
<span class="n">BLACK</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #666666;">0</span> <span class="p">,</span><span class="mi" style="color: #666666;">0</span> <span class="p">,</span><span class="mi" style="color: #666666;">0</span> <span class="p">)</span>
<span class="n">WHITE</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #666666;">255</span><span class="p">,</span><span class="mi" style="color: #666666;">255</span><span class="p">,</span><span class="mi" style="color: #666666;">255</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the arena the game will be played in. </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawArena</span><span class="p">():</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">((</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">))</span>
<span class="c" style="color: #408080; font-style: italic;">#Draw outline of arena</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">),(</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">)),</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #666666;">2</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draw centre line</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">),</span><span class="mi" style="color: #666666;">0</span><span class="p">),((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">),</span><span class="n">WINDOWHEIGHT</span><span class="p">),</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">4</span><span class="p">))</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the paddle</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawPaddle</span><span class="p">(</span><span class="n">paddle</span><span class="p">):</span>
<span class="c" style="color: #408080; font-style: italic;">#Stops paddle moving too low</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span>
<span class="c" style="color: #408080; font-style: italic;">#Stops paddle moving too high</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">=</span> <span class="n">LINETHICKNESS</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws paddle</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">paddle</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#draws the ball</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">):</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">ball</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#moves the ball returns new position</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">moveBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">):</span>
<span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">x</span> <span class="o" style="color: #666666;">+=</span> <span class="n">ballDirX</span>
<span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="n">ballDirY</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">ball</span>
<span class="c" style="color: #408080; font-style: italic;">#Checks for a collision with a wall, and 'bounces' ball off it.</span>
<span class="c" style="color: #408080; font-style: italic;">#Returns new direction</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">checkEdgeCollision</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">):</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="p">)</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">or</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">):</span>
<span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirY</span> <span class="o" style="color: #666666;">*</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="p">)</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">or</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">):</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">*</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span>
<span class="c" style="color: #408080; font-style: italic;">#Checks is the ball has hit a paddle, and 'bounces' ball off it. </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">checkHitBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">paddle1</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">):</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #666666;">1</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;">==</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span> <span class="k" style="color: green; font-weight: bold;">return</span> <span class="mi" style="color: #666666;">1</span>
<span class="c" style="color: #408080; font-style: italic;">#Artificial Intelligence of computer player </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">artificialIntelligence</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">):</span>
<span class="c" style="color: #408080; font-style: italic;">#If ball is moving away from paddle, center bat</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;"><</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">):</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;">></span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">):</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">-=</span> <span class="mi" style="color: #666666;">1</span>
<span class="c" style="color: #408080; font-style: italic;">#if ball moving towards bat, track its movement. </span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #666666;">1</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">y</span><span class="p">:</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">-=</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">paddle2</span>
<span class="c" style="color: #408080; font-style: italic;">#Main function</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">main</span><span class="p">():</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">init</span><span class="p">()</span>
<span class="k" style="color: green; font-weight: bold;">global</span> <span class="n">DISPLAYSURF</span>
<span class="n">FPSCLOCK</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">time</span><span class="o" style="color: #666666;">.</span><span class="n">Clock</span><span class="p">()</span>
<span class="n">DISPLAYSURF</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_mode</span><span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_caption</span><span class="p">(</span><span class="s" style="color: #ba2121;">'Pong'</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Initiate variable and set starting positions</span>
<span class="c" style="color: #408080; font-style: italic;">#any future changes made within rectangles</span>
<span class="n">ballX</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">ballY</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">playerOnePosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">playerTwoPosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="c" style="color: #408080; font-style: italic;">#Keeps track of ball direction</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="c" style="color: #408080; font-style: italic;">## -1 = left 1 = right</span>
<span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="c" style="color: #408080; font-style: italic;">## -1 = up 1 = down</span>
<span class="c" style="color: #408080; font-style: italic;">#Creates Rectangles for ball and paddles.</span>
<span class="n">paddle1</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">PADDLEOFFSET</span><span class="p">,</span><span class="n">playerOnePosition</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span><span class="n">PADDLESIZE</span><span class="p">)</span>
<span class="n">paddle2</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLEOFFSET</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">,</span> <span class="n">playerTwoPosition</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span><span class="n">PADDLESIZE</span><span class="p">)</span>
<span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">ballX</span><span class="p">,</span> <span class="n">ballY</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the starting position of the Arena</span>
<span class="n">drawArena</span><span class="p">()</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle1</span><span class="p">)</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle2</span><span class="p">)</span>
<span class="n">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">)</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">mouse</span><span class="o" style="color: #666666;">.</span><span class="n">set_visible</span><span class="p">(</span><span class="mi" style="color: #666666;">0</span><span class="p">)</span> <span class="c" style="color: #408080; font-style: italic;"># make cursor invisible</span>
<span class="k" style="color: green; font-weight: bold;">while</span> <span class="bp" style="color: green;">True</span><span class="p">:</span> <span class="c" style="color: #408080; font-style: italic;">#main game loop</span>
<span class="k" style="color: green; font-weight: bold;">for</span> <span class="n">event</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">in</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">():</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">QUIT</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">quit</span><span class="p">()</span>
<span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span>
<span class="c" style="color: #408080; font-style: italic;"># mouse movement commands</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">MOUSEMOTION</span><span class="p">:</span>
<span class="n">mousex</span><span class="p">,</span> <span class="n">mousey</span> <span class="o" style="color: #666666;">=</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">pos</span>
<span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">=</span> <span class="n">mousey</span>
<span class="n">drawArena</span><span class="p">()</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle1</span><span class="p">)</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle2</span><span class="p">)</span>
<span class="n">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">)</span>
<span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">moveBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">)</span>
<span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="n">checkEdgeCollision</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">)</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">*</span> <span class="n">checkHitBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">paddle1</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">)</span>
<span class="n">paddle2</span> <span class="o" style="color: #666666;">=</span> <span class="n">artificialIntelligence</span> <span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">)</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span>
<span class="n">FPSCLOCK</span><span class="o" style="color: #666666;">.</span><span class="n">tick</span><span class="p">(</span><span class="n">FPS</span><span class="p">)</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">__name__</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #ba2121;">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span></pre>
<br />
You should now have your paddle moving around the screen nicely using the mouse and the computers paddle moving using its artificial intelligence.<br />
<br />
However we have not programmed the software to allow the ball to collide with the paddles, so let us do that now.<br />
<br />
As always lets call the function in our main loop to ensure it is checked every-time the FPS ticks over.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">*</span> <span class="n">checkHitBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">paddle1</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">)</span></pre>
<br />
We know that when the ball hits the paddle we will want to reverse the direction the ball is moving in in X.<br />
<br />
If we make our function checkHitBall return a -1 if the ball is hit, and a 1 if it is not, then by multiplying this returned value by the value in ballDirX will give us the new ballDirX. This is similar to how we reversed the direction if the ball hit one of the sides.<br />
<br />
So below our checkEdgeCollision function lets add a checkHitBall function.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #408080; font-style: italic;">#Checks is the ball has hit a paddle, and 'bounces' ball off it. </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">checkHitBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">paddle1</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">):</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #666666;">1</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;">==</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span> <span class="k" style="color: green; font-weight: bold;">return</span> <span class="mi" style="color: #666666;">1</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
As this function checks if the ball has hit either paddle, we pass both paddles and the ball into the function.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">checkHitBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">paddle1</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">):</span></pre>
<br />
Now the fun bit of seeing if the ball has hit the paddle. Pygame has a few ways of doing this such as checking to see if one rectangle has intersected another. I want to make sure my ball can only be hit from the front and not the back<br />
<br />
<span style="background-color: #f8f8f8; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;"> </span><span class="k" style="color: green; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; font-weight: bold; letter-spacing: 0.015em; line-height: 15.600000381469727px;">if</span><span style="background-color: #f8f8f8; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;"> </span><span class="n" style="font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">ballDirX</span><span style="background-color: #f8f8f8; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;"> </span><span class="o" style="color: #666666; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">==</span><span style="background-color: #f8f8f8; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;"> </span><span class="o" style="color: #666666; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">-</span><span class="mi" style="color: #666666; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">1</span><span style="background-color: #f8f8f8; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;"> </span><span class="ow" style="color: #aa22ff; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; font-weight: bold; letter-spacing: 0.015em; line-height: 15.600000381469727px;">and</span><span style="background-color: #f8f8f8; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;"> </span><span class="n" style="font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">paddle1</span><span class="o" style="color: #666666; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">.</span><span class="n" style="font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">right</span><span style="background-color: #f8f8f8; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;"> </span><span class="o" style="color: #666666; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">==</span><span style="background-color: #f8f8f8; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;"> </span><span class="n" style="font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">ball</span><span class="o" style="color: #666666; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">.</span><span class="n" style="font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">left</span><span style="background-color: #f8f8f8; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;"> </span><span class="ow" style="color: #aa22ff; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; font-weight: bold; letter-spacing: 0.015em; line-height: 15.600000381469727px;">and</span><span style="background-color: #f8f8f8; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;"> </span><span class="n" style="font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">paddle1</span><span class="o" style="color: #666666; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">.</span><span class="n" style="font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">top</span><span style="background-color: #f8f8f8; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;"> </span><span class="o" style="color: #666666; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;"><</span><span style="background-color: #f8f8f8; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;"> </span><span class="n" style="font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">ball</span><span class="o" style="color: #666666; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">.</span><span class="n" style="font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">top</span><span style="background-color: #f8f8f8; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;"> </span><span class="ow" style="color: #aa22ff; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; font-weight: bold; letter-spacing: 0.015em; line-height: 15.600000381469727px;">and</span><span style="background-color: #f8f8f8; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;"> </span><span class="n" style="font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">paddle1</span><span class="o" style="color: #666666; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">.</span><span class="n" style="font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">bottom</span><span style="background-color: #f8f8f8; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;"> </span><span class="o" style="color: #666666; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">></span><span style="background-color: #f8f8f8; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;"> </span><span class="n" style="font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">ball</span><span class="o" style="color: #666666; font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">.</span><span class="n" style="font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">bottom</span><span class="p" style="font-family: "consolas" , "dejavu sans mono" , "bitstream vera sans mono" , monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px;">:</span><br />
<br />
This line checks four things to see if the ball has been hit.<br />
The first things it checks the direction of the ball. We only want to ball to be classed as being hit if it is hits the paddle from the front. If it is hit from the rear it means you have missed the ball, so we will make the ball pass through the paddle until it is back in play.<br />
The next three things it checks are to see the position of the ball relative to the paddle. It checks if the right hand side of the paddle hits the left hand side of the ball AND that the top of the ball is lower than the top of the paddle AND the bottom of the ball is higher than the bottom of the paddle.<br />
<br />
If these three AND statements are true, then the paddle has hit the ball so we return a -1 to flip the direction.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">return</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
We now do something very similar but for the computer paddle which is paddle 2. Notice we want the ball to be moving in a different direction and the right hand side of the ball will hit the left side of the paddle. <br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #666666;">1</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;">==</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span></pre>
<br />
Finally if nothing has been hit we should return a 1 so the direction of the ball doesn't change.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span> <span class="k" style="color: green; font-weight: bold;">return</span> <span class="mi" style="color: #666666;">1</span></pre>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKDchEAv23SykQDf__8n85eVhxMAk5pWvj22OAWruW4zP1ns3c8rOmhLb36CT3xkmtW8bXBxsI5MWd95PMJfm3cqCGNajDSTA2g2CqkspjqtLaHKveZ9h59NJ3pmyMiqdwl7T1SGF4gd8/s1600/pong-stage7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKDchEAv23SykQDf__8n85eVhxMAk5pWvj22OAWruW4zP1ns3c8rOmhLb36CT3xkmtW8bXBxsI5MWd95PMJfm3cqCGNajDSTA2g2CqkspjqtLaHKveZ9h59NJ3pmyMiqdwl7T1SGF4gd8/s1600/pong-stage7.png" width="320" /></a></div>
<br />
<br />
<b><u>Step 8 - Add a scoring system</u></b><br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: green; font-weight: bold;">import</span> <span class="nn" style="color: blue; font-weight: bold;">pygame</span><span class="o" style="color: #666666;">,</span> <span class="nn" style="color: blue; font-weight: bold;">sys</span>
<span class="kn" style="color: green; font-weight: bold;">from</span> <span class="nn" style="color: blue; font-weight: bold;">pygame.locals</span> <span class="kn" style="color: green; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="c" style="color: #408080; font-style: italic;"># Number of frames per second</span>
<span class="c" style="color: #408080; font-style: italic;"># Change this value to speed up or slow down your game</span>
<span class="n">FPS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">200</span>
<span class="c" style="color: #408080; font-style: italic;">#Global Variables to be used through our program</span>
<span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">400</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">300</span>
<span class="n">LINETHICKNESS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">10</span>
<span class="n">PADDLESIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">50</span>
<span class="n">PADDLEOFFSET</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">20</span>
<span class="c" style="color: #408080; font-style: italic;"># Set up the colours</span>
<span class="n">BLACK</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #666666;">0</span> <span class="p">,</span><span class="mi" style="color: #666666;">0</span> <span class="p">,</span><span class="mi" style="color: #666666;">0</span> <span class="p">)</span>
<span class="n">WHITE</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #666666;">255</span><span class="p">,</span><span class="mi" style="color: #666666;">255</span><span class="p">,</span><span class="mi" style="color: #666666;">255</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the arena the game will be played in. </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawArena</span><span class="p">():</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">((</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">))</span>
<span class="c" style="color: #408080; font-style: italic;">#Draw outline of arena</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">),(</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">)),</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #666666;">2</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draw centre line</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">),</span><span class="mi" style="color: #666666;">0</span><span class="p">),((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">),</span><span class="n">WINDOWHEIGHT</span><span class="p">),</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">4</span><span class="p">))</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the paddle</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawPaddle</span><span class="p">(</span><span class="n">paddle</span><span class="p">):</span>
<span class="c" style="color: #408080; font-style: italic;">#Stops paddle moving too low</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span>
<span class="c" style="color: #408080; font-style: italic;">#Stops paddle moving too high</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">=</span> <span class="n">LINETHICKNESS</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws paddle</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">paddle</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#draws the ball</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">):</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">ball</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#moves the ball returns new position</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">moveBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">):</span>
<span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">x</span> <span class="o" style="color: #666666;">+=</span> <span class="n">ballDirX</span>
<span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="n">ballDirY</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">ball</span>
<span class="c" style="color: #408080; font-style: italic;">#Checks for a collision with a wall, and 'bounces' ball off it.</span>
<span class="c" style="color: #408080; font-style: italic;">#Returns new direction</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">checkEdgeCollision</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">):</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="p">)</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">or</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">):</span>
<span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirY</span> <span class="o" style="color: #666666;">*</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="p">)</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">or</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">):</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">*</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span>
<span class="c" style="color: #408080; font-style: italic;">#Checks is the ball has hit a paddle, and 'bounces' ball off it. </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">checkHitBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">paddle1</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">):</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #666666;">1</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;">==</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span> <span class="k" style="color: green; font-weight: bold;">return</span> <span class="mi" style="color: #666666;">1</span>
<span class="c" style="color: #408080; font-style: italic;">#Checks to see if a point has been scored returns new score</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">checkPointScored</span><span class="p">(</span><span class="n">paddle1</span><span class="p">,</span> <span class="n">ball</span><span class="p">,</span> <span class="n">score</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">):</span>
<span class="c" style="color: #408080; font-style: italic;">#reset points if left wall is hit</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;">==</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="mi" style="color: #666666;">0</span>
<span class="c" style="color: #408080; font-style: italic;">#1 point for hitting the ball</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span><span class="p">:</span>
<span class="n">score</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">score</span>
<span class="c" style="color: #408080; font-style: italic;">#5 points for beating the other paddle</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">score</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">5</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">score</span>
<span class="c" style="color: #408080; font-style: italic;">#if no points scored, return score unchanged</span>
<span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span> <span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">score</span>
<span class="c" style="color: #408080; font-style: italic;">#Artificial Intelligence of computer player </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">artificialIntelligence</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">):</span>
<span class="c" style="color: #408080; font-style: italic;">#If ball is moving away from paddle, center bat</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;"><</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">):</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;">></span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">):</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">-=</span> <span class="mi" style="color: #666666;">1</span>
<span class="c" style="color: #408080; font-style: italic;">#if ball moving towards bat, track its movement. </span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #666666;">1</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span><span class="p">:</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">-=</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">paddle2</span>
<span class="c" style="color: #408080; font-style: italic;">#Displays the current score on the screen</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">displayScore</span><span class="p">(</span><span class="n">score</span><span class="p">):</span>
<span class="n">resultSurf</span> <span class="o" style="color: #666666;">=</span> <span class="n">BASICFONT</span><span class="o" style="color: #666666;">.</span><span class="n">render</span><span class="p">(</span><span class="s" style="color: #ba2121;">'Score = </span><span class="si" style="color: #bb6688; font-style: italic; font-weight: bold;">%s</span><span class="s" style="color: #ba2121;">'</span> <span class="o" style="color: #666666;">%</span><span class="p">(</span><span class="n">score</span><span class="p">),</span> <span class="bp" style="color: green;">True</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">)</span>
<span class="n">resultRect</span> <span class="o" style="color: #666666;">=</span> <span class="n">resultSurf</span><span class="o" style="color: #666666;">.</span><span class="n">get_rect</span><span class="p">()</span>
<span class="n">resultRect</span><span class="o" style="color: #666666;">.</span><span class="n">topleft</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="mi" style="color: #666666;">150</span><span class="p">,</span> <span class="mi" style="color: #666666;">25</span><span class="p">)</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">blit</span><span class="p">(</span><span class="n">resultSurf</span><span class="p">,</span> <span class="n">resultRect</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Main function</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">main</span><span class="p">():</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">init</span><span class="p">()</span>
<span class="k" style="color: green; font-weight: bold;">global</span> <span class="n">DISPLAYSURF</span>
<span class="c" style="color: #408080; font-style: italic;">##Font information</span>
<span class="k" style="color: green; font-weight: bold;">global</span> <span class="n">BASICFONT</span><span class="p">,</span> <span class="n">BASICFONTSIZE</span>
<span class="n">BASICFONTSIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">20</span>
<span class="n">BASICFONT</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">font</span><span class="o" style="color: #666666;">.</span><span class="n">Font</span><span class="p">(</span><span class="s" style="color: #ba2121;">'freesansbold.ttf'</span><span class="p">,</span> <span class="n">BASICFONTSIZE</span><span class="p">)</span>
<span class="n">FPSCLOCK</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">time</span><span class="o" style="color: #666666;">.</span><span class="n">Clock</span><span class="p">()</span>
<span class="n">DISPLAYSURF</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_mode</span><span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_caption</span><span class="p">(</span><span class="s" style="color: #ba2121;">'Pong'</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Initiate variable and set starting positions</span>
<span class="c" style="color: #408080; font-style: italic;">#any future changes made within rectangles</span>
<span class="n">ballX</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">ballY</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">playerOnePosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">playerTwoPosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">score</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">0</span>
<span class="c" style="color: #408080; font-style: italic;">#Keeps track of ball direction</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="c" style="color: #408080; font-style: italic;">## -1 = left 1 = right</span>
<span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="c" style="color: #408080; font-style: italic;">## -1 = up 1 = down</span>
<span class="c" style="color: #408080; font-style: italic;">#Creates Rectangles for ball and paddles.</span>
<span class="n">paddle1</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">PADDLEOFFSET</span><span class="p">,</span><span class="n">playerOnePosition</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span><span class="n">PADDLESIZE</span><span class="p">)</span>
<span class="n">paddle2</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLEOFFSET</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">,</span> <span class="n">playerTwoPosition</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span><span class="n">PADDLESIZE</span><span class="p">)</span>
<span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">ballX</span><span class="p">,</span> <span class="n">ballY</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the starting position of the Arena</span>
<span class="n">drawArena</span><span class="p">()</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle1</span><span class="p">)</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle2</span><span class="p">)</span>
<span class="n">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">)</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">mouse</span><span class="o" style="color: #666666;">.</span><span class="n">set_visible</span><span class="p">(</span><span class="mi" style="color: #666666;">0</span><span class="p">)</span> <span class="c" style="color: #408080; font-style: italic;"># make cursor invisible</span>
<span class="k" style="color: green; font-weight: bold;">while</span> <span class="bp" style="color: green;">True</span><span class="p">:</span> <span class="c" style="color: #408080; font-style: italic;">#main game loop</span>
<span class="k" style="color: green; font-weight: bold;">for</span> <span class="n">event</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">in</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">():</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">QUIT</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">quit</span><span class="p">()</span>
<span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span>
<span class="c" style="color: #408080; font-style: italic;"># mouse movement commands</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">MOUSEMOTION</span><span class="p">:</span>
<span class="n">mousex</span><span class="p">,</span> <span class="n">mousey</span> <span class="o" style="color: #666666;">=</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">pos</span>
<span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">=</span> <span class="n">mousey</span>
<span class="n">drawArena</span><span class="p">()</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle1</span><span class="p">)</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle2</span><span class="p">)</span>
<span class="n">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">)</span>
<span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">moveBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">)</span>
<span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="n">checkEdgeCollision</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">)</span>
<span class="n">score</span> <span class="o" style="color: #666666;">=</span> <span class="n">checkPointScored</span><span class="p">(</span><span class="n">paddle1</span><span class="p">,</span> <span class="n">ball</span><span class="p">,</span> <span class="n">score</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">)</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">*</span> <span class="n">checkHitBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">paddle1</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">)</span>
<span class="n">paddle2</span> <span class="o" style="color: #666666;">=</span> <span class="n">artificialIntelligence</span> <span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">)</span>
<span class="n">displayScore</span><span class="p">(</span><span class="n">score</span><span class="p">)</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span>
<span class="n">FPSCLOCK</span><span class="o" style="color: #666666;">.</span><span class="n">tick</span><span class="p">(</span><span class="n">FPS</span><span class="p">)</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">__name__</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #ba2121;">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span></pre>
<br />
Right we should have the majority of our game written, so how about adding a display of the score?<br />
<br />
We will do this in two parts. First we will update the score and then we will display the score.<br />
<br />
Before we write our function to update the score lets call that function in our main program.<br />
<br />
We only want the score to change if the ball has hit the paddle while moving in a certain direction. Therefore we need to call the function to check the score before we update the ball direction once it has been hit.<br />
<br />
Add this line in the main function before you check the ball is hit, but after you have checked edge collision.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">score</span> <span class="o" style="color: #666666;">=</span> <span class="n">checkPointScored</span><span class="p">(</span><span class="n">paddle1</span><span class="p">,</span> <span class="n">ball</span><span class="p">,</span> <span class="n">score</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">)</span></pre>
<br />
This line updates the variable score with whatever is returned from the checkPointScored function. What have we forgotten? We need to initiate the variable 'score' as we have with the other variables.<br />
<br />
So underneath the line <br />
<br />
playerTwoPosition = (WINDOWHEIGHT - PADDLESIZE) /2<br />
<br />
add<br />
<br />
Score = 0<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">playerTwoPosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">score</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">0</span></pre>
<br />
Now we can write our function which will check if any points have been scored and update the score to reflect this.<br />
<br />
Our checkPointScored function takes the position of paddle 1, the position of the ball, the current score and the direction of the ball to help determine if a point has been scored.<br />
<br />
You can decide how and when points are scored if you want to. My function gives 5 points for beating the computers paddle and one point for hitting the ball. If your paddle is beaten, then your points are reset to 0.<br />
<br />
The whole of the function looks as follows.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #408080; font-style: italic;">#Checks to see if a point has been scored returns new score</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">checkPointScored</span><span class="p">(</span><span class="n">paddle1</span><span class="p">,</span> <span class="n">ball</span><span class="p">,</span> <span class="n">score</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">):</span>
<span class="c" style="color: #408080; font-style: italic;">#reset points if left wall is hit</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;">==</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="mi" style="color: #666666;">0</span>
<span class="c" style="color: #408080; font-style: italic;">#1 point for hitting the ball</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span><span class="p">:</span>
<span class="n">score</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">score</span>
<span class="c" style="color: #408080; font-style: italic;">#5 points for beating the other paddle</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">score</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">5</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">score</span>
<span class="c" style="color: #408080; font-style: italic;">#if no points scored, return score unchanged</span>
<span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span> <span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">score</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
As always we define the name of the function and the parameters being passed into it.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">checkPointScored</span><span class="p">(</span><span class="n">paddle1</span><span class="p">,</span> <span class="n">ball</span><span class="p">,</span> <span class="n">score</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">):</span></pre>
<br />
We then check to see if the players paddle has been beaten.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #408080; font-style: italic;">#reset points if left wall is hit</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;">==</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="mi" style="color: #666666;">0</span></pre>
<br />
If the ball makes it to the left hand side of the arena, we return 0 i.e. reset the score to 0.<br />
<br />
Now we look to see if your paddle has been hit. We use the same check we carried out to see if we had hit the ball. We then increase the score by one and return it.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #408080; font-style: italic;">#1 point for hitting the ball</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span><span class="p">:</span>
<span class="n">score</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">score</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
Now we see if the computer paddle has been beaten. This is very similar to seeing if your own paddle has been passed by the ball. This time we check the right hand side of the ball and the right hand edge of the arena.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #408080; font-style: italic;">#5 points for beating the other paddle</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">score</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">5</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">score</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
If this happens we add 5 onto the score and return that.<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
If nothing has happened to cause the score to change we return the score unaffected.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #408080; font-style: italic;">#if no points scored, return score unchanged</span>
<span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span> <span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">score</span></pre>
<br />
That was all very straight forward wasn't it?<br />
<br />
Now we have worked out what our score should be, we need to display the score.<br />
<br />
In our main function we will call a function to display the score.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">displayScore</span><span class="p">(</span><span class="n">score</span><span class="p">)</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
Before we write the function we will have to create some information about the font we want to use to display the score.<br />
<br />
Underneath global DISPLAYNAME at the top of our main function add the following.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #408080; font-style: italic;">##Font information</span>
<span class="k" style="color: green; font-weight: bold;">global</span> <span class="n">BASICFONT</span><span class="p">,</span> <span class="n">BASICFONTSIZE</span>
<span class="n">BASICFONTSIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">20</span>
<span class="n">BASICFONT</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">font</span><span class="o" style="color: #666666;">.</span><span class="n">Font</span><span class="p">(</span><span class="s" style="color: #ba2121;">'freesansbold.ttf'</span><span class="p">,</span> <span class="n">BASICFONTSIZE</span><span class="p">)</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
This creates a global variable called BASICFONT and another called BASICFONTSIZE.<br />
<br />
We then set BASICFONTSIZE to 20<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">BASICFONTSIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">20</span></pre>
<br />
and set the font to freesansbold<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">BASICFONT</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">font</span><span class="o" style="color: #666666;">.</span><span class="n">Font</span><span class="p">(</span><span class="s" style="color: #ba2121;">'freesansbold.ttf'</span><span class="p">,</span> <span class="n">BASICFONTSIZE</span><span class="p">)</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
Now we can write the function which displays the score.<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #408080; font-style: italic;">#Displays the current score on the screen</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">displayScore</span><span class="p">(</span><span class="n">score</span><span class="p">):</span>
<span class="n">resultSurf</span> <span class="o" style="color: #666666;">=</span> <span class="n">BASICFONT</span><span class="o" style="color: #666666;">.</span><span class="n">render</span><span class="p">(</span><span class="s" style="color: #ba2121;">'Score = </span><span class="si" style="color: #bb6688; font-style: italic; font-weight: bold;">%s</span><span class="s" style="color: #ba2121;">'</span> <span class="o" style="color: #666666;">%</span><span class="p">(</span><span class="n">score</span><span class="p">),</span> <span class="bp" style="color: green;">True</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">)</span>
<span class="n">resultRect</span> <span class="o" style="color: #666666;">=</span> <span class="n">resultSurf</span><span class="o" style="color: #666666;">.</span><span class="n">get_rect</span><span class="p">()</span>
<span class="n">resultRect</span><span class="o" style="color: #666666;">.</span><span class="n">topleft</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="mi" style="color: #666666;">150</span><span class="p">,</span> <span class="mi" style="color: #666666;">25</span><span class="p">)</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">blit</span><span class="p">(</span><span class="n">resultSurf</span><span class="p">,</span> <span class="n">resultRect</span><span class="p">)</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
The first line creates a new surface called resultSurf. <br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">resultSurf</span> <span class="o" style="color: #666666;">=</span> <span class="n">BASICFONT</span><span class="o" style="color: #666666;">.</span><span class="n">render</span><span class="p">(</span><span class="s" style="color: #ba2121;">'Score = </span><span class="si" style="color: #bb6688; font-style: italic; font-weight: bold;">%s</span><span class="s" style="color: #ba2121;">'</span> <span class="o" style="color: #666666;">%</span><span class="p">(</span><span class="n">score</span><span class="p">),</span> <span class="bp" style="color: green;">True</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">)</span></pre>
<br />
It then takes the information from BASICFONT and renders it with the following information defined within the brackets.<br />
<br />
'Score = %s' %(score)<br />
<br />
This explains the text to be displayed. It will say 'Score = %s' where %s is replaced by whatever follows the %. In our case the value stored in the variable score.<br />
<br />
Therefore if the score was 4 we would see.<br />
<br />
Score = 4<br />
<br />
True refers to the fact we want anti-aliasing turned on. I will not go into the technical details of how this achieves its results, as it is beyond the scope of this tutorial. If you are curious then replace True with False and look at how blocky the font looks!<br />
<br />
WHITE defines the colour and uses the information we stored in the global variable when we defined the WHITE and BLACK earlier in our program.<br />
<br />
The next line<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">resultRect</span> <span class="o" style="color: #666666;">=</span> <span class="n">resultSurf</span><span class="o" style="color: #666666;">.</span><span class="n">get_rect</span><span class="p">()</span></pre>
<br />
This creates a new rectangle called resultRect which is the same size as the surface we created on the previous line. It uses a built in function of pygame called get_rect().<br />
<br />
Next we position the new rectangle<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">resultRect</span><span class="o" style="color: #666666;">.</span><span class="n">topleft</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="mi" style="color: #666666;">150</span><span class="p">,</span> <span class="mi" style="color: #666666;">25</span><span class="p">)</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
This places the text 'WINDOWWIDTH - 150' in X which is 150 pixels from the right hand side of the screen, and 25 pixels from the top in Y.<br />
<br />
Finally we display the surface with<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">blit</span><span class="p">(</span><span class="n">resultSurf</span><span class="p">,</span> <span class="n">resultRect</span><span class="p">)</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
which uses blit to update just the part of the screen specified by resultRect, which we have just created to match the size of our surface.<br />
<br />
There we go, you should have a fully working game of pong.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEju_IDbRZ5e3kMryuq6aMbTeyi_RD5bFVVWElYqZFPU8fQz2jC4tZkISJhdP0aGIL12kbMtdJYgAeyAITwmtyc6SKPoFySkQQy14T_dvt8bcxpx07h_lpzHuOeENHFmBMzCPLC1jFLjX28/s1600/pong-stage8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEju_IDbRZ5e3kMryuq6aMbTeyi_RD5bFVVWElYqZFPU8fQz2jC4tZkISJhdP0aGIL12kbMtdJYgAeyAITwmtyc6SKPoFySkQQy14T_dvt8bcxpx07h_lpzHuOeENHFmBMzCPLC1jFLjX28/s1600/pong-stage8.png" width="320" /></a></div>
<br />
<br />
<b><u>Stage 9 - Speed Optimisation</u></b><br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="kn" style="color: green; font-weight: bold;">import</span> <span class="nn" style="color: blue; font-weight: bold;">pygame</span><span class="o" style="color: #666666;">,</span> <span class="nn" style="color: blue; font-weight: bold;">sys</span>
<span class="kn" style="color: green; font-weight: bold;">from</span> <span class="nn" style="color: blue; font-weight: bold;">pygame.locals</span> <span class="kn" style="color: green; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="c" style="color: #408080; font-style: italic;"># Number of frames per second</span>
<span class="c" style="color: #408080; font-style: italic;"># Change this value to speed up or slow down your game</span>
<span class="n">FPS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">40</span>
<span class="n">INCREASESPEED</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">5</span>
<span class="c" style="color: #408080; font-style: italic;">#Global Variables to be used through our program</span>
<span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">400</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">300</span>
<span class="n">LINETHICKNESS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">10</span>
<span class="n">PADDLESIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">50</span>
<span class="n">PADDLEOFFSET</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">20</span>
<span class="c" style="color: #408080; font-style: italic;"># Set up the colours</span>
<span class="n">BLACK</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #666666;">0</span> <span class="p">,</span><span class="mi" style="color: #666666;">0</span> <span class="p">,</span><span class="mi" style="color: #666666;">0</span> <span class="p">)</span>
<span class="n">WHITE</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #666666;">255</span><span class="p">,</span><span class="mi" style="color: #666666;">255</span><span class="p">,</span><span class="mi" style="color: #666666;">255</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the arena the game will be played in. </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawArena</span><span class="p">():</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">((</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">))</span>
<span class="c" style="color: #408080; font-style: italic;">#Draw outline of arena</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="mi" style="color: #666666;">0</span><span class="p">,</span><span class="mi" style="color: #666666;">0</span><span class="p">),(</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">)),</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #666666;">2</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draw centre line</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">),</span><span class="mi" style="color: #666666;">0</span><span class="p">),((</span><span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">),</span><span class="n">WINDOWHEIGHT</span><span class="p">),</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">4</span><span class="p">))</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the paddle</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawPaddle</span><span class="p">(</span><span class="n">paddle</span><span class="p">):</span>
<span class="c" style="color: #408080; font-style: italic;">#Stops paddle moving too low</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span>
<span class="c" style="color: #408080; font-style: italic;">#Stops paddle moving too high</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">paddle</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">=</span> <span class="n">LINETHICKNESS</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws paddle</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">paddle</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#draws the ball</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">):</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="n">ball</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#moves the ball returns new position</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">moveBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">):</span>
<span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">x</span> <span class="o" style="color: #666666;">+=</span> <span class="p">(</span><span class="n">ballDirX</span> <span class="o" style="color: #666666;">*</span> <span class="n">INCREASESPEED</span><span class="p">)</span>
<span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="p">(</span><span class="n">ballDirY</span> <span class="o" style="color: #666666;">*</span> <span class="n">INCREASESPEED</span><span class="p">)</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">ball</span>
<span class="c" style="color: #408080; font-style: italic;">#Checks for a collision with a wall, and 'bounces' ball off it.</span>
<span class="c" style="color: #408080; font-style: italic;">#Returns new direction</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">checkEdgeCollision</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">):</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="p">)</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">or</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">):</span>
<span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirY</span> <span class="o" style="color: #666666;">*</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">LINETHICKNESS</span><span class="p">)</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">or</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">):</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">*</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span>
<span class="c" style="color: #408080; font-style: italic;">#Checks is the ball has hit a paddle, and 'bounces' ball off it. </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">checkHitBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">paddle1</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">):</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #666666;">1</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;">==</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span> <span class="k" style="color: green; font-weight: bold;">return</span> <span class="mi" style="color: #666666;">1</span>
<span class="c" style="color: #408080; font-style: italic;">#Checks to see if a point has been scored returns new score</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">checkPointScored</span><span class="p">(</span><span class="n">paddle1</span><span class="p">,</span> <span class="n">ball</span><span class="p">,</span> <span class="n">score</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">):</span>
<span class="c" style="color: #408080; font-style: italic;">#reset points if left wall is hit</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="o" style="color: #666666;">==</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="mi" style="color: #666666;">0</span>
<span class="c" style="color: #408080; font-style: italic;">#1 point for hitting the ball</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">left</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">top</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">and</span> <span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span> <span class="o" style="color: #666666;">></span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">bottom</span><span class="p">:</span>
<span class="n">score</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">1</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">score</span>
<span class="c" style="color: #408080; font-style: italic;">#5 points for beating the other paddle</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">right</span> <span class="o" style="color: #666666;">==</span> <span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">:</span>
<span class="n">score</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #666666;">5</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">score</span>
<span class="c" style="color: #408080; font-style: italic;">#if no points scored, return score unchanged</span>
<span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span> <span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">score</span>
<span class="c" style="color: #408080; font-style: italic;">#Artificial Intelligence of computer player </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">artificialIntelligence</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">):</span>
<span class="c" style="color: #408080; font-style: italic;">#If ball is moving away from paddle, center bat</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;"><</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">):</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="n">INCREASESPEED</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;">></span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">):</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">-=</span> <span class="n">INCREASESPEED</span>
<span class="c" style="color: #408080; font-style: italic;">#if ball moving towards bat, track its movement. </span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #666666;">1</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span><span class="p">:</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="n">INCREASESPEED</span>
<span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">-=</span> <span class="n">INCREASESPEED</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">paddle2</span>
<span class="c" style="color: #408080; font-style: italic;">#Displays the current score on the screen</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">displayScore</span><span class="p">(</span><span class="n">score</span><span class="p">):</span>
<span class="n">resultSurf</span> <span class="o" style="color: #666666;">=</span> <span class="n">BASICFONT</span><span class="o" style="color: #666666;">.</span><span class="n">render</span><span class="p">(</span><span class="s" style="color: #ba2121;">'Score = </span><span class="si" style="color: #bb6688; font-style: italic; font-weight: bold;">%s</span><span class="s" style="color: #ba2121;">'</span> <span class="o" style="color: #666666;">%</span><span class="p">(</span><span class="n">score</span><span class="p">),</span> <span class="bp" style="color: green;">True</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">)</span>
<span class="n">resultRect</span> <span class="o" style="color: #666666;">=</span> <span class="n">resultSurf</span><span class="o" style="color: #666666;">.</span><span class="n">get_rect</span><span class="p">()</span>
<span class="n">resultRect</span><span class="o" style="color: #666666;">.</span><span class="n">topleft</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="mi" style="color: #666666;">150</span><span class="p">,</span> <span class="mi" style="color: #666666;">25</span><span class="p">)</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">blit</span><span class="p">(</span><span class="n">resultSurf</span><span class="p">,</span> <span class="n">resultRect</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Main function</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">main</span><span class="p">():</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">init</span><span class="p">()</span>
<span class="k" style="color: green; font-weight: bold;">global</span> <span class="n">DISPLAYSURF</span>
<span class="c" style="color: #408080; font-style: italic;">##Font information</span>
<span class="k" style="color: green; font-weight: bold;">global</span> <span class="n">BASICFONT</span><span class="p">,</span> <span class="n">BASICFONTSIZE</span>
<span class="n">BASICFONTSIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">20</span>
<span class="n">BASICFONT</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">font</span><span class="o" style="color: #666666;">.</span><span class="n">Font</span><span class="p">(</span><span class="s" style="color: #ba2121;">'freesansbold.ttf'</span><span class="p">,</span> <span class="n">BASICFONTSIZE</span><span class="p">)</span>
<span class="n">FPSCLOCK</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">time</span><span class="o" style="color: #666666;">.</span><span class="n">Clock</span><span class="p">()</span>
<span class="n">DISPLAYSURF</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_mode</span><span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_caption</span><span class="p">(</span><span class="s" style="color: #ba2121;">'Pong'</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Initiate variable and set starting positions</span>
<span class="c" style="color: #408080; font-style: italic;">#any future changes made within rectangles</span>
<span class="n">ballX</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWWIDTH</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">ballY</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">playerOnePosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">playerTwoPosition</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLESIZE</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span>
<span class="n">score</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">0</span>
<span class="c" style="color: #408080; font-style: italic;">#Keeps track of ball direction</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="c" style="color: #408080; font-style: italic;">## -1 = left 1 = right</span>
<span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span> <span class="c" style="color: #408080; font-style: italic;">## -1 = up 1 = down</span>
<span class="c" style="color: #408080; font-style: italic;">#Creates Rectangles for ball and paddles.</span>
<span class="n">paddle1</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">PADDLEOFFSET</span><span class="p">,</span><span class="n">playerOnePosition</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span><span class="n">PADDLESIZE</span><span class="p">)</span>
<span class="n">paddle2</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">-</span> <span class="n">PADDLEOFFSET</span> <span class="o" style="color: #666666;">-</span> <span class="n">LINETHICKNESS</span><span class="p">,</span> <span class="n">playerTwoPosition</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span><span class="n">PADDLESIZE</span><span class="p">)</span>
<span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">Rect</span><span class="p">(</span><span class="n">ballX</span><span class="p">,</span> <span class="n">ballY</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">,</span> <span class="n">LINETHICKNESS</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#Draws the starting position of the Arena</span>
<span class="n">drawArena</span><span class="p">()</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle1</span><span class="p">)</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle2</span><span class="p">)</span>
<span class="n">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">)</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">mouse</span><span class="o" style="color: #666666;">.</span><span class="n">set_visible</span><span class="p">(</span><span class="mi" style="color: #666666;">0</span><span class="p">)</span> <span class="c" style="color: #408080; font-style: italic;"># make cursor invisible</span>
<span class="k" style="color: green; font-weight: bold;">while</span> <span class="bp" style="color: green;">True</span><span class="p">:</span> <span class="c" style="color: #408080; font-style: italic;">#main game loop</span>
<span class="k" style="color: green; font-weight: bold;">for</span> <span class="n">event</span> <span class="ow" style="color: #aa22ff; font-weight: bold;">in</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">():</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">QUIT</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">quit</span><span class="p">()</span>
<span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span>
<span class="c" style="color: #408080; font-style: italic;"># mouse movement commands</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">MOUSEMOTION</span><span class="p">:</span>
<span class="n">mousex</span><span class="p">,</span> <span class="n">mousey</span> <span class="o" style="color: #666666;">=</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">pos</span>
<span class="n">paddle1</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">=</span> <span class="n">mousey</span>
<span class="n">drawArena</span><span class="p">()</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle1</span><span class="p">)</span>
<span class="n">drawPaddle</span><span class="p">(</span><span class="n">paddle2</span><span class="p">)</span>
<span class="n">drawBall</span><span class="p">(</span><span class="n">ball</span><span class="p">)</span>
<span class="n">ball</span> <span class="o" style="color: #666666;">=</span> <span class="n">moveBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">)</span>
<span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span> <span class="o" style="color: #666666;">=</span> <span class="n">checkEdgeCollision</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">)</span>
<span class="n">score</span> <span class="o" style="color: #666666;">=</span> <span class="n">checkPointScored</span><span class="p">(</span><span class="n">paddle1</span><span class="p">,</span> <span class="n">ball</span><span class="p">,</span> <span class="n">score</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">)</span>
<span class="n">ballDirX</span> <span class="o" style="color: #666666;">=</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">*</span> <span class="n">checkHitBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">paddle1</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">)</span>
<span class="n">paddle2</span> <span class="o" style="color: #666666;">=</span> <span class="n">artificialIntelligence</span> <span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">)</span>
<span class="c" style="color: #408080; font-style: italic;">#displayScore(score)</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span>
<span class="n">FPSCLOCK</span><span class="o" style="color: #666666;">.</span><span class="n">tick</span><span class="p">(</span><span class="n">FPS</span><span class="p">)</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">__name__</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #ba2121;">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span></pre>
<br />
So we now have a fully working game of PONG. What do you feel about the speed of the game. For me it runs very well on my PC, a little slow on my Mac and very slow on my Raspberry Pi. Some of you will be able to tweak the value set in FPS to slow down or speed up the game. However if your system is running flat out what can you do to speed it up?<br />
<br />
The main reason the game slows down is because it struggles to refresh the screen at the desired FPS. Quite a common problem in Pygame.<br />
<br />
There are a few options to help improve the situation. You can do one or all of the following.<br />
<br />
<b>Increase movement per frame.</b><br />
<br />
Well at the moment you are moving the ball only one pixel per frame. We can increase this.<br />
<br />
Under the line where you defined the FPS add the following line.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="n">INCREASESPEED</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #666666;">5</span></pre>
<br />
Now when you move the ball in the moveBall function instead of increasing its location by one, increase it by 5 using the following.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #408080; font-style: italic;">#moves the ball returns new position</span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">moveBall</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">ballDirY</span><span class="p">):</span>
<span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">x</span> <span class="o" style="color: #666666;">+=</span> <span class="p">(</span><span class="n">ballDirX</span> <span class="o" style="color: #666666;">*</span> <span class="n">INCREASESPEED</span><span class="p">)</span>
<span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="p">(</span><span class="n">ballDirY</span> <span class="o" style="color: #666666;">*</span> <span class="n">INCREASESPEED</span><span class="p">)</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">ball</span></pre>
<br />
To ensure the computers paddle is not massively slow in relation to this you should also make a similar change in the artificialIntelligence function.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><span class="c" style="color: #408080; font-style: italic;">#Artificial Intelligence of computer player </span>
<span class="k" style="color: green; font-weight: bold;">def</span> <span class="nf" style="color: blue;">artificialIntelligence</span><span class="p">(</span><span class="n">ball</span><span class="p">,</span> <span class="n">ballDirX</span><span class="p">,</span> <span class="n">paddle2</span><span class="p">):</span>
<span class="c" style="color: #408080; font-style: italic;">#If ball is moving away from paddle, center bat</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="o" style="color: #666666;">-</span><span class="mi" style="color: #666666;">1</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;"><</span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">):</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="n">INCREASESPEED</span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;">></span> <span class="p">(</span><span class="n">WINDOWHEIGHT</span><span class="o" style="color: #666666;">/</span><span class="mi" style="color: #666666;">2</span><span class="p">):</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">-=</span> <span class="n">INCREASESPEED</span>
<span class="c" style="color: #408080; font-style: italic;">#if ball moving towards bat, track its movement. </span>
<span class="k" style="color: green; font-weight: bold;">elif</span> <span class="n">ballDirX</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #666666;">1</span><span class="p">:</span>
<span class="k" style="color: green; font-weight: bold;">if</span> <span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span> <span class="o" style="color: #666666;"><</span> <span class="n">ball</span><span class="o" style="color: #666666;">.</span><span class="n">centery</span><span class="p">:</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">+=</span> <span class="n">INCREASESPEED</span>
<span class="k" style="color: green; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">paddle2</span><span class="o" style="color: #666666;">.</span><span class="n">y</span> <span class="o" style="color: #666666;">-=</span> <span class="n">INCREASESPEED</span>
<span class="k" style="color: green; font-weight: bold;">return</span> <span class="n">paddle2</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
Instead of increasing the paddle position by a value of 1 it increases it by the value stored in INCREASESPEED.<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
There is a warning with this method of increasing the speed. While the value 5 works in this case, increasing the value of INCREASESPEED may mean the paddles do not recognise when the ball is hit or the ball does not bounce off the side of the arena. The ball jumps by 5 pixels, which is ok. If it jumps by 10 or 20 it may not detect collision with the wall or paddle and will appear to pass through them.<br />
<br />
Another option is simply don't display the score!<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
One thing which slows the game down more than anything is the displaying of the score. So to stop this slowing down the game, don't display the score!<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
Place a hash tag in front of the line displayScore(score) and this will stop the screen updating the score.<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 15.600000381469727px; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"> <span class="c" style="color: #408080; font-style: italic;">#displayScore(score)</span></pre>
<br />
I hope you have enjoyed writing this game of pong as much as I did. Hopefully you have learned a few new Pygame tools to aid you with programming your own games!<br />
<br />
<b>Update</b><br />
<b><br /></b>Since writing this blog post Nat over at <a href="https://www.webucator.com/programming/python.cfm" target="_blank">Webucator</a> has turned this blog post into an excellent video tutorial which refactors the code using OOP. Its definitely worth having a look at the video they have created, which I discuss in a later blog post. <br />
<br />
<div style="text-align: center;">
<a href="http://trevorappleton.blogspot.co.uk/2015/04/refactoring-pong-using-object-oriented.html" target="_blank">Refactoring Pong using Object Oriented Python</a></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: left;">
<b>Further Update</b></div>
<div class="separator" style="clear: both; text-align: left;">
<b><br /></b></div>
<div class="separator" style="clear: both; text-align: left;">
The wonderful MagPi magazine have used this blog post as the basis of one of their tutorials. Check it out in Issue 53 of the MagPi (Page 26/27). </div>
<br />
<div style="text-align: center;">
<a href="https://www.raspberrypi.org/magpi-issues/MagPi53.pdf">https://www.raspberrypi.org/magpi-issues/MagPi53.pdf</a></div>
Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com146tag:blogger.com,1999:blog-8250429656532783188.post-4588508843473185022014-03-24T12:28:00.001+00:002014-03-24T12:30:35.152+00:00Remotely modify a text file on your Raspberry PiMy last blog post explained <a href="http://trevorappleton.blogspot.co.uk/2014/03/remotely-copy-files-to-and-from-your.html" target="_blank">how to transfer files to and from your Raspberry Pi using FileZilla</a>. It made use of SFTP (SSH File Transfer Protocol).<br />
<br />
If I am programming and would like to remotely modify a Python file which is on my Raspberry Pi, I can do this through the command line. I would SSH into the Raspberry Pi and probably using nano (I do keep meaning to learn vim!) I can modify the file. It works really well.<br />
<br />
However sometimes I find it a little clunky. I think it would be nice if I could use one of my favourite text editors on my computer to do this. As it happens SFTP is integrated into various other programs to make it easier to remotely modify a file already on your Raspberry Pi.<br />
<br />
Now I know text editors, and which is the best one to use, has been debated to death for years. vi vs. emacs being the longest running battle probably ever. This battle even has its own wiki page <a href="http://en.wikipedia.org/wiki/Editor_war">http://en.wikipedia.org/wiki/Editor_war</a>. It can be a very emotive subject for many people.<br />
<br />
I happen to like Notepad++ on Windows and TextWrangler on the mac. Both these can remotely log into your Raspberry Pi to modify text files.<br />
<br />
As with FileZilla in my previous blog post this is very easy to set up.<br />
<br />
First TextWrangler.<br />
<br />
Click on File and then Open from FTP/SFTP Server... in the drop down menu.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSNLkc3m8IccT5isITGXfOi31NEdr2Uy4i8K5oakr7Ft8Hg2ITLR9cdBjnuSAbSnAc1XKTQX9kwJHMHQ1OoAdY9k8AEo0z_kL7sYMLtKERh3Ars_D1Ycrs8lrG_BuXoNbAhaI-44PTax8/s1600/TextWranglerConnect.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSNLkc3m8IccT5isITGXfOi31NEdr2Uy4i8K5oakr7Ft8Hg2ITLR9cdBjnuSAbSnAc1XKTQX9kwJHMHQ1OoAdY9k8AEo0z_kL7sYMLtKERh3Ars_D1Ycrs8lrG_BuXoNbAhaI-44PTax8/s1600/TextWranglerConnect.png" height="120" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
A new window should open, click on Connect...<br />
<br />
This will open up yet another window as below.<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4hlqfdi5I_YqxJNdslS9P0lBwIu9C94W_Wt6ygklxZ5-dDwzZItZ9vUobYLHyG7Ty7TyJWvAwvLs1J1_X332UwBkPHel3rqgkICv4FJF5VxfXowrG5V0oXJvEGEcGz8Hqy1QvtnMcvSM/s1600/TextWranglerDetails.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4hlqfdi5I_YqxJNdslS9P0lBwIu9C94W_Wt6ygklxZ5-dDwzZItZ9vUobYLHyG7Ty7TyJWvAwvLs1J1_X332UwBkPHel3rqgkICv4FJF5VxfXowrG5V0oXJvEGEcGz8Hqy1QvtnMcvSM/s1600/TextWranglerDetails.png" height="173" width="320" /></a></div>
<br />
<br />
Fill in the following details:<br />
<ul>
<li>The IP Address of your Raspberry Pi. </li>
<li>Check the SFTP Box.</li>
<li>Type in your Raspberry Pi User Name. </li>
<li>Type in your Raspberry Pi Password. </li>
</ul>
<div>
If you are unsure of your IP address of your Raspberry Pi this <a href="http://trevorappleton.blogspot.co.uk/2013/03/remotely-find-raspberry-pi-ip-address.html" target="_blank">blog post</a> will help you out. </div>
<div>
<br /></div>
<div>
Your screen should look like this (but with your Raspberry Pi IP address.) </div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpnwR8qcB17JYc712LyDAJ99hpp6OSsh9vDSQVeR_Clce7V4RWjR6or_hFufjkrbue0W3ze8zjznj8jGvTmF17x7FuuzbAcDI8dVnY0CxfsKTZEqTmQnsL6w4QuJDrHeEsRSoNJDmZEMs/s1600/TextWranglerSFTP.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpnwR8qcB17JYc712LyDAJ99hpp6OSsh9vDSQVeR_Clce7V4RWjR6or_hFufjkrbue0W3ze8zjznj8jGvTmF17x7FuuzbAcDI8dVnY0CxfsKTZEqTmQnsL6w4QuJDrHeEsRSoNJDmZEMs/s1600/TextWranglerSFTP.png" height="175" width="320" /></a></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div>
<br /></div>
<div>
You can now click on Connect.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5oijAkU0MFZoyS0lQDf_rBiTrawOu77Y7oXNwXifG1xDtys8VQiNilSVX2OPzlzyrMRYazk3rtSinJFEA-cqx6fnY5nt_msK1Euy2YkFakQ_v_C80PQO17t4wUHL3JOVdsCAW54hAppc/s1600/TextWranglerSFTPFileNavigation.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5oijAkU0MFZoyS0lQDf_rBiTrawOu77Y7oXNwXifG1xDtys8VQiNilSVX2OPzlzyrMRYazk3rtSinJFEA-cqx6fnY5nt_msK1Euy2YkFakQ_v_C80PQO17t4wUHL3JOVdsCAW54hAppc/s1600/TextWranglerSFTPFileNavigation.png" height="386" width="400" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
You can now navigate through the file structure to the file you want to open. Once you have found it you can click on Open. </div>
<div>
<br /></div>
<div>
The file will now be open in TextWrangler, and you can modify it as normal. </div>
<div>
<br /></div>
<div>
It is a very similar process using Notepad++.<br />
<br />
You should click on Plugins, and then on NppFTP, and check the Show NppFTP Window. This will open up a window on the right hand side of the text editor.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjKcXB4sbKTBpdpgwC0UWg3PZUxBiCYakn51OGSZf_SROp86Kg4txp2L9E8syXT2Fs22xumCtG-Je5mEBEcb9g3yZjBlxgASNt8z-8AySxmSSpkW7OG5viDlOuSTVZtil2_MygxvKq6k0/s1600/NppFTP_show_window.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjKcXB4sbKTBpdpgwC0UWg3PZUxBiCYakn51OGSZf_SROp86Kg4txp2L9E8syXT2Fs22xumCtG-Je5mEBEcb9g3yZjBlxgASNt8z-8AySxmSSpkW7OG5viDlOuSTVZtil2_MygxvKq6k0/s1600/NppFTP_show_window.PNG" height="400" width="338" /></a></div>
<br />
<br />
<br /></div>
<div>
Now you should click on the Settings icon which is at the Right hand side of this additional window. It looks like a little cog wheel. When an option of General Settings or Profile Settings appears, you should select Profile Settings.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgllG62u6RGlVBdFQKAMvnF_nCMmVNJDAnZ18OPg7IrQM5bBpX_z1y8OeVsE4J9SrFN7p76PEeUvJj58nf5jZqgATz8MbUzqCx9M5iAfvY2UQnDx71e-mOMQmS9sm0NuHJTyGbuuaZaINE/s1600/NppFTP_profile_settings.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgllG62u6RGlVBdFQKAMvnF_nCMmVNJDAnZ18OPg7IrQM5bBpX_z1y8OeVsE4J9SrFN7p76PEeUvJj58nf5jZqgATz8MbUzqCx9M5iAfvY2UQnDx71e-mOMQmS9sm0NuHJTyGbuuaZaINE/s1600/NppFTP_profile_settings.PNG" height="320" width="400" /></a></div>
<br /></div>
<div>
<br />
In this new window you should do the following.<br />
<br />
<ul>
<li>Click Add New. </li>
<li>When asked to enter a profile name type Raspberry Pi and click OK.</li>
<li>Type your Raspberry Pi's IP address.</li>
<li>Change connection type to SFTP.</li>
<li>Type in your Raspberry Pi Username.</li>
<li>Type in your Raspberry Pi Password.</li>
</ul>
<br />
Once you have completed your settings as below, with your own details, you can click Close.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifB6fLUUiTkVlEQJIkZ36JEA7aEDLrvQldGkg2McGBBJkLDzfw8JzoRNbmaVxC4ta0vl4BfRXuKE7uz4gW4vxqrg2pDOKNSDfJUxJ9V8opttzXrfLyR6YkNI3LpWS1Fqp2et2dV8qt0jI/s1600/NppFTP_completed_settings.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifB6fLUUiTkVlEQJIkZ36JEA7aEDLrvQldGkg2McGBBJkLDzfw8JzoRNbmaVxC4ta0vl4BfRXuKE7uz4gW4vxqrg2pDOKNSDfJUxJ9V8opttzXrfLyR6YkNI3LpWS1Fqp2et2dV8qt0jI/s1600/NppFTP_completed_settings.PNG" height="320" width="400" /></a></div>
<br />
Now to connect or disconnect to your Raspberry Pi click the little blue Dis(Connect) icon in the NppFTP window.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglWosaYW153Ga5GAMgKz4cnHPx_2Z6bKe04ip2LXw9rxKcCRkTUgyOlncYqoXXUcT-2vwXupSwCLQbSlAgnQ_HE8YLw_8iRiD2PoawU6-khUs9JYm5s7_GztBWcNRCfu0kjAy_dzqMaaI/s1600/NppFTP_Disconnect.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglWosaYW153Ga5GAMgKz4cnHPx_2Z6bKe04ip2LXw9rxKcCRkTUgyOlncYqoXXUcT-2vwXupSwCLQbSlAgnQ_HE8YLw_8iRiD2PoawU6-khUs9JYm5s7_GztBWcNRCfu0kjAy_dzqMaaI/s1600/NppFTP_Disconnect.PNG" height="163" width="400" /></a></div>
<br />
<br />
And then select the Raspberry Pi option from the drop down menu.<br />
<br />
You will now be connected to your Raspberry Pi and can open any files you want to by selecting them from the folder structure in the window below.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8oK-QAkJoBW7gRZOk9FnDMJUd1pMdhVlyhUu1rhX5lwgDJLTwpO46FQqMZtN0oBBldDbYWwOUd1yk8ZO58M5QU6smQPN-wNMwCuPxyRj6Hkqheg0jmWUz8nBC-iS9IOH23vHPyiI_5_g/s1600/NppFP_Connected.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8oK-QAkJoBW7gRZOk9FnDMJUd1pMdhVlyhUu1rhX5lwgDJLTwpO46FQqMZtN0oBBldDbYWwOUd1yk8ZO58M5QU6smQPN-wNMwCuPxyRj6Hkqheg0jmWUz8nBC-iS9IOH23vHPyiI_5_g/s1600/NppFP_Connected.PNG" height="400" width="341" /></a></div>
<br /></div>
<div>
<br />
If you prefer a different text editor to the ones I have mentioned above, why not see if it has the functionality to connect via FTP? <br />
<br />
While I am make no claim that this is the best way to do this, or the only way, it is something I have found useful, and I am sure many of you will too!</div>
Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com2tag:blogger.com,1999:blog-8250429656532783188.post-55331618757767824682014-03-11T12:06:00.002+00:002014-03-11T12:15:28.616+00:00Remotely copy files to and from your Raspberry Pi.Most of the time I remotely log into my Raspberry Pi. Depending on what I am doing I will either <a href="http://trevorappleton.blogspot.co.uk/2013/03/ssh-into-raspberry-pi.html" target="_blank">SSH</a> into it or <a href="http://trevorappleton.blogspot.co.uk/2013/03/remotely-connect-to-raspberry-pi-desktop.html" target="_blank">VNC</a> into it, which allows me to do almost whatever I would like to.<br />
<br />
I say almost as there is a caveat.<br />
<br />
What happens when I want to transfer a file to or from the Raspberry Pi?<br />
<br />
I have to find a memory stick, plug it into my computer, copy the files onto it, unplug it, plug it into my Raspberry Pi, go back to my computer, copy the files over...<br />
<br />
Then if I happen to modify a file and want to transfer it back I go through the whole process again.<br />
<br />
What an absolute pain!<br />
<br />
There must be a better way... Well you will be pleased to know there is!<br />
<br />
The secret is using SSH File Transfer Protocol or SFTP. (SSH stands for Secure Shell.)<br />
<br />
Once you know how to use this, and it really is simple, it opens up a whole world of really cool options.<br />
<br />
Lets start simple, and work out how to transfer files to and from your Raspberry Pi.<br />
<br />
There are a number of programs you can download to help you out with this, but if you are new to this, I recommend FileZilla.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://upload.wikimedia.org/wikipedia/commons/0/01/FileZilla_logo.svg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://upload.wikimedia.org/wikipedia/commons/0/01/FileZilla_logo.svg" height="200" width="200" /></a></div>
<br />
<br />
You will want the client and not the server version. You can download it from this link.<br />
<br />
<div style="text-align: center;">
<a href="https://filezilla-project.org/">https://filezilla-project.org/</a></div>
<br />
There is a version for Windows, Linux and Mac OSX.<br />
<br />
Once installed, load the program. You should see a screen like this.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4GwbNnQt6FrtF7gPL0d9CwK75GS7i0Cngh9CLFfrpKElcFh0Efyp_skPEL5y5S6VZGuKS7RXzBGzDmaqZubaxT3FypJ2_AX0WKt-hOJnEP6iULPNViJzXihMmCBoRVp1zihtdplNWUlE/s1600/FileZilla.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4GwbNnQt6FrtF7gPL0d9CwK75GS7i0Cngh9CLFfrpKElcFh0Efyp_skPEL5y5S6VZGuKS7RXzBGzDmaqZubaxT3FypJ2_AX0WKt-hOJnEP6iULPNViJzXihMmCBoRVp1zihtdplNWUlE/s1600/FileZilla.PNG" height="331" width="400" /></a></div>
<br />
<br />
Now click on File and then Site Manager.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiez390UHQHyFqHBLdZI5eRZ2wX8Rqc_K-Uvj3h9i2T_GQeI5v4polEowTiVkw-2VOlAc6ryNnQogdGGu9G5_AYDreQTKHXGcsnPP3C94RQbJFtpNC5nva6q1IGC0S65ehlEm2H5ZJWnP0/s1600/FileZilla_SiteManager.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiez390UHQHyFqHBLdZI5eRZ2wX8Rqc_K-Uvj3h9i2T_GQeI5v4polEowTiVkw-2VOlAc6ryNnQogdGGu9G5_AYDreQTKHXGcsnPP3C94RQbJFtpNC5nva6q1IGC0S65ehlEm2H5ZJWnP0/s1600/FileZilla_SiteManager.PNG" height="337" width="400" /></a></div>
<br />
<br />
Now you should click on New Site and make the following changes:<br />
<ul>
<li>In the entry box next to Host type in the IP address of your Raspberry Pi. If you are unsure of this, you can follow an <a href="http://trevorappleton.blogspot.co.uk/2013/03/remotely-find-raspberry-pi-ip-address.html" target="_blank">earlier blog post of mine </a>which helps you to determine this. </li>
<li>Protocol should be changed to SFTP - SSH File Transfer Prototcol.</li>
<li>Logon Type should be Normal</li>
<li>Type in your User name in the box below this</li>
<li>Your login Password goes into the box below. </li>
<li>Using the Rename button I have renamed my connection to Raspberry Pi. You dont have to do this, but it helps you identify your connection.</li>
</ul>
<div>
Your screen should look something like this.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivlAXm9XvBvUfLX2lNCJQQZ3fpBgxhaEzVaVeLiCG9ph60mCnCsSfHhdc0wq-ZiK6pOX8wH3TFuOFONyRjWmHaZflPA-fNjB4SoJSnhvIjTj9ml3phpE-adqEqzYVVAz-yqDw7isuztcc/s1600/FileZilla_SiteManager_Complete.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivlAXm9XvBvUfLX2lNCJQQZ3fpBgxhaEzVaVeLiCG9ph60mCnCsSfHhdc0wq-ZiK6pOX8wH3TFuOFONyRjWmHaZflPA-fNjB4SoJSnhvIjTj9ml3phpE-adqEqzYVVAz-yqDw7isuztcc/s1600/FileZilla_SiteManager_Complete.PNG" height="337" width="400" /></a></div>
<div>
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
You can now click on connect.<br />
<br />
You may get a message warning you that the server's host key is unknown. You can just click OK if this box appears.<br />
<br />
Your FileZilla window will now look as follows.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-JEdjjvthcTBWiEgHNlkzYizkQGcqRUw7qqdWO-MRCFJkz4pXSdWD7mAvcJjPGu3vb9b92KA1h9G0HU62AVeQlT04r4IItOeBC0OPWHAHp10hpZACbzkrc4cLkuh7F-0WE9ektvMOEOc/s1600/FileZilla_SiteManager_Connected.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-JEdjjvthcTBWiEgHNlkzYizkQGcqRUw7qqdWO-MRCFJkz4pXSdWD7mAvcJjPGu3vb9b92KA1h9G0HU62AVeQlT04r4IItOeBC0OPWHAHp10hpZACbzkrc4cLkuh7F-0WE9ektvMOEOc/s1600/FileZilla_SiteManager_Connected.PNG" height="331" width="400" /></a></div>
<br />
On the left hand side you can see under the Local Site there is a window which shows you the folder structure of your system. Underneath that there is a window which shows information of the files and folders of any folder you chose in the folder structure.<br />
<br />
This is repeated on the right hand side but for the file / folder structure on the Raspberry Pi.<br />
<br />
To transfer files to you Raspberry Pi<br />
<br />
<ul>
<li>Navigate to the folder you would like to place the files into using the right hand windows. </li>
<li>Navigate to the files or folders you would like to copy over in the left hand windows. </li>
<li>Right click on the files or folders and chose "Upload"</li>
</ul>
<div>
The file will start to copy over to the selected folder. </div>
<div>
<br /></div>
<div>
A similar process is used to transfer files from your Raspberry Pi.</div>
<div>
<br /></div>
<ul>
<li>Navigate to the folder you would like to place the files into using the left hand windows. </li>
<li>Navigate to the files or folders you would like to copy over in the right hand windows. </li>
<li>Right click on the files or folders and chose "Download"</li>
</ul>
<div>
</div>
<br />
<div>
This will copy files from your Raspberry Pi.<br />
<br />
In the future your information should be saved into FileZilla, so you can just click on File then Site Manager, select the Raspberry Pi connection you have set up and then click connect. Simple!<br />
<br />
I am sure a lot of you will find the use of SFTP very simple but effective, and you will no longer be searching around for a memory stick to copy files to your Raspberry Pi.</div>
<br />Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com41tag:blogger.com,1999:blog-8250429656532783188.post-37375959592802412812014-01-06T12:22:00.000+00:002015-03-09T09:40:07.920+00:00Creating an Animation Studio with a Raspberry Pi and PythonWhen I was younger I used to love the character Morph. For those of you too young to remember, he was an animated plasticine model who appeared alongside Tony Hart.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://upload.wikimedia.org/wikipedia/en/thumb/e/ec/Morph-NMM-Bradford.jpg/220px-Morph-NMM-Bradford.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://upload.wikimedia.org/wikipedia/en/thumb/e/ec/Morph-NMM-Bradford.jpg/220px-Morph-NMM-Bradford.jpg" /></a></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px; text-align: left;">Image courtesy of <a href="http://www.flickr.com/photos/giles72/2530851077/" target="_blank">Giles Farrington via Flickr</a></span></div>
<br />
<br />
He was created by Aardman Animations who went on to create other animated films such as Wallace and Gromit and Chicken Run. I often thought that it would have been great fun to create my own plasticine models and capture them on film. There was one small problem... making plasticine models was one thing, filming them and turning them into a film was something else!!<br />
<br />
After finishing my blog which turned a <a href="http://www.trevorappleton.blogspot.co.uk/2013/11/creating-time-lapse-camera-with.html" target="_blank">Raspberry Pi and camera into a time-lapse camera</a> I started to think about this. It's not a great leap to go from making time-lapse movies to animation movies. I also thought while I am at it, why not wrap it up with a nice user interface?<br />
<br />
What a great idea for a blog post I thought ...<br />
<br />
... so here is the Python code for your very own Raspberry Pi animation studio! All you need is a Raspberry Pi, a camera for your Pi and the contents of this blog.<br />
<br />
This is written in Python 2.7 and not Python 3. To get started you will need to use the IDLE icon on your Raspberry Pi rather than the IDLE 3 icon. For those of you new to the Python world, don't spend too much time worrying if you should using Python 2 or 3. Its easy to change from one to another. I am using Python 2.7 for this program as we will need access to some libraries, which are not available yet in Python 3.<br />
<br />
Before we dive into the code lets think about what we want to achieve.<br />
<br />
<ul>
<li>We probably want a Graphical User Interface (GUI) to make things look nice.</li>
<li>We definitely want to be able to take pictures, and save them to add into our film.</li>
<li>We all make mistakes, so we want to delete a frame if we are not happy with it.</li>
<li>We probably want to be able to scroll through our frames to see what they look like.</li>
<li>We want to turn our images into a film, and we may want to adjust some inputs to tweak that process.</li>
</ul>
<br />
<br />
Sounds as though we have the basic structure of our program defined.<br />
<br />
Before we embark on this, if you have not already done so please read my blog post explaining <a href="http://trevorappleton.blogspot.co.uk/2013/05/python-rock-paper-scissors-inside-gui.html" target="_blank">how to get started with Tkinter </a>(For the GUI) and my <a href="http://trevorappleton.blogspot.co.uk/2013/11/creating-time-lapse-camera-with.html" target="_blank">time-lapse blog</a>. I will borrow heavily from both of these blogs, as if you have some code written which works... why would you write it again from scratch? In fact I keep all my code I have written and am always referring back to it, which I think is good practice, and one you should adopt!<br />
<br />
One final word before you get started, I would recommend you save your work very often, just in case!<br />
<br />
Lets get started!<br />
<br />
The first thing we need to do is to install a few libraries which we need to run this program. We will be using a tool called avconv. This can be installed by typing the following into a command line.<br />
<br />
sudo apt-get install -y libav-tools<br />
<br />
You will also need to install python-imaging-tk<br />
<br />
sudo apt-get install -y python-imaging-tk<br />
<br />
First of all here it the complete program. Have a read through it and see which parts you understand. If you have followed my previous blogs it should all be quite straight forward. We will then break it down into more detail in a minute.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="kn" style="color: #007020; font-weight: bold;">from</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">Tkinter</span> <span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="kn" style="color: #007020; font-weight: bold;">from</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">ttk</span> <span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">os</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">glob</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">Image</span><span class="o" style="color: #666666;">,</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">ImageTk</span>
<span class="c" style="color: #60a0b0; font-style: italic;">## Functions to select frames</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">firstFrame</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">countFrames</span><span class="p">()</span><span class="o" style="color: #666666;">></span><span class="mi" style="color: #40a070;">0</span><span class="p">:</span>
<span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;">#If there are any frames</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;">#Set to 0 if there are none</span>
<span class="n">updateGUI</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">lastFrame</span><span class="p">():</span>
<span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="n">countFrames</span><span class="p">())</span>
<span class="n">updateGUI</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">nextFrame</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">()</span> <span class="o" style="color: #666666;"><</span> <span class="p">(</span><span class="n">countFrames</span><span class="p">()):</span>
<span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">()</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span>
<span class="n">updateGUI</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">prevFrame</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">()</span> <span class="o" style="color: #666666;">></span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">()</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span>
<span class="n">updateGUI</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">takeFrame</span><span class="p">():</span>
<span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="n">countFrames</span><span class="p">()</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span>
<span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">system</span><span class="p">(</span><span class="s" style="color: #4070a0;">"raspistill -o image</span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">.jpg"</span><span class="o" style="color: #666666;">%</span><span class="p">(</span><span class="n">setZero</span><span class="p">()))</span>
<span class="n">updateGUI</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Deletes the last stored frame</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">deleteFrame</span><span class="p">():</span>
<span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="n">countFrames</span><span class="p">())</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">countFrames</span><span class="p">()</span> <span class="o" style="color: #666666;">></span> <span class="mi" style="color: #40a070;">0</span><span class="p">:</span>
<span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">remove</span><span class="p">(</span><span class="s" style="color: #4070a0;">'image</span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">.jpg'</span><span class="o" style="color: #666666;">%</span><span class="n">setZero</span><span class="p">())</span>
<span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="n">countFrames</span><span class="p">())</span>
<span class="n">updateGUI</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Returns the number of jpg files in the directory.</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">countFrames</span><span class="p">():</span>
<span class="n">openFiles</span> <span class="o" style="color: #666666;">=</span> <span class="n">glob</span><span class="o" style="color: #666666;">.</span><span class="n">glob</span><span class="p">(</span><span class="s" style="color: #4070a0;">'image*.jpg'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="nb" style="color: #007020;">len</span><span class="p">(</span><span class="n">openFiles</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">## sets the right number of zeros for the frameNumber</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">setZero</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="nb" style="color: #007020;">str</span><span class="p">(</span><span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">())</span><span class="o" style="color: #666666;">.</span><span class="n">zfill</span><span class="p">(</span><span class="mi" style="color: #40a070;">7</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Updates the image in the GUI and refreshes</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">updateGUI</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">countFrames</span><span class="p">()</span><span class="o" style="color: #666666;">></span><span class="mi" style="color: #40a070;">0</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;"># Checks to see if there are any existing frames</span>
<span class="n">fileName</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">"image</span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">.jpg"</span><span class="o" style="color: #666666;">%</span><span class="n">setZero</span><span class="p">()</span>
<span class="n">inFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">Image</span><span class="o" style="color: #666666;">.</span><span class="n">open</span><span class="p">(</span><span class="n">fileName</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">## Resize image to suit GUI</span>
<span class="c" style="color: #60a0b0; font-style: italic;">## Was 2592 x 1944 - Divide both of these by 6</span>
<span class="n">newSizeFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">resize</span><span class="p">((</span><span class="mi" style="color: #40a070;">400</span><span class="p">,</span><span class="mi" style="color: #40a070;">300</span><span class="p">))</span>
<span class="n">displayFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">ImageTk</span><span class="o" style="color: #666666;">.</span><span class="n">PhotoImage</span><span class="p">(</span><span class="n">newSizeFile</span><span class="p">)</span><span class="c" style="color: #60a0b0; font-style: italic;">#Convert to Tkinter compatible</span>
<span class="n">Label</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">image</span><span class="o" style="color: #666666;">=</span><span class="n">displayFile</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'WE'</span><span class="p">,</span><span class="n">columnspan</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">)</span>
<span class="n">root</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span><span class="c" style="color: #60a0b0; font-style: italic;">#Refreshes</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">frameImage</span> <span class="o" style="color: #666666;">=</span> <span class="n">PhotoImage</span><span class="p">(</span><span class="nb" style="color: #007020;">file</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">"blankScreen.gif"</span><span class="p">)</span>
<span class="n">Label</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">image</span><span class="o" style="color: #666666;">=</span><span class="n">frameImage</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'WE'</span><span class="p">,</span><span class="n">columnspan</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">)</span>
<span class="n">root</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span>
<span class="c" style="color: #60a0b0; font-style: italic;">## Creates the video file.</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">createFilm</span><span class="p">():</span>
<span class="n">setfpsIn</span> <span class="o" style="color: #666666;">=</span> <span class="n">fpsIn</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">()</span>
<span class="n">setfpsOut</span> <span class="o" style="color: #666666;">=</span> <span class="n">fpsOut</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">()</span>
<span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">system</span><span class="p">(</span><span class="s" style="color: #4070a0;">"avconv -r </span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;"> -i image</span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">.jpg -r </span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;"> -vcodec libx264 -crf 20 -g 15 -vf crop=2592:1458,scale=1280:720 timelapse.mp4"</span><span class="o" style="color: #666666;">%</span><span class="p">(</span><span class="n">setfpsIn</span><span class="p">,</span><span class="s" style="color: #4070a0;">'</span><span class="si" style="color: #70a0d0; font-style: italic;">%7d</span><span class="s" style="color: #4070a0;">'</span><span class="p">,</span><span class="n">setfpsOut</span><span class="p">))</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Setup of main GUI</span>
<span class="n">root</span> <span class="o" style="color: #666666;">=</span> <span class="n">Tk</span><span class="p">()</span>
<span class="n">root</span><span class="o" style="color: #666666;">.</span><span class="n">title</span> <span class="p">(</span><span class="s" style="color: #4070a0;">'Animation Studio'</span><span class="p">)</span>
<span class="n">root</span><span class="o" style="color: #666666;">.</span><span class="n">geometry</span><span class="p">(</span><span class="s" style="color: #4070a0;">"410x450"</span><span class="p">)</span>
<span class="n">mainframe</span> <span class="o" style="color: #666666;">=</span> <span class="n">Frame</span><span class="p">(</span><span class="n">root</span><span class="p">,</span> <span class="n">padding</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'3 3 12 12'</span><span class="p">)</span>
<span class="n">mainframe</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="n">sticky</span><span class="o" style="color: #666666;">=</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="n">W</span><span class="p">,</span><span class="n">E</span><span class="p">,</span><span class="n">S</span><span class="p">))</span>
<span class="n">mainframe</span><span class="o" style="color: #666666;">.</span><span class="n">columnconfigure</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="n">weight</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span>
<span class="n">mainframe</span><span class="o" style="color: #666666;">.</span><span class="n">rowconfigure</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="n">weight</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Variables</span>
<span class="n">frameNumber</span> <span class="o" style="color: #666666;">=</span> <span class="n">IntVar</span><span class="p">()</span>
<span class="n">fpsIn</span> <span class="o" style="color: #666666;">=</span> <span class="n">IntVar</span><span class="p">()</span>
<span class="n">fpsOut</span> <span class="o" style="color: #666666;">=</span> <span class="n">IntVar</span><span class="p">()</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Set Variables</span>
<span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="n">countFrames</span><span class="p">())</span>
<span class="n">fpsIn</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="mi" style="color: #40a070;">10</span><span class="p">)</span>
<span class="n">fpsOut</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="mi" style="color: #40a070;">24</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Frame Select</span>
<span class="n">Button</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">text</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">"<<"</span><span class="p">,</span> <span class="n">command</span> <span class="o" style="color: #666666;">=</span> <span class="n">firstFrame</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'WE'</span><span class="p">)</span>
<span class="n">Button</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">text</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">"<"</span><span class="p">,</span> <span class="n">command</span> <span class="o" style="color: #666666;">=</span> <span class="n">prevFrame</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'WE'</span><span class="p">)</span>
<span class="n">Button</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">text</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">">"</span><span class="p">,</span> <span class="n">command</span> <span class="o" style="color: #666666;">=</span> <span class="n">nextFrame</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">4</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'WE'</span><span class="p">)</span>
<span class="n">Button</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">text</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">">>"</span><span class="p">,</span> <span class="n">command</span> <span class="o" style="color: #666666;">=</span> <span class="n">lastFrame</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'WE'</span><span class="p">)</span>
<span class="n">Entry</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">textvariable</span> <span class="o" style="color: #666666;">=</span> <span class="n">frameNumber</span><span class="p">,</span> <span class="n">width</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">7</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">3</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'WE'</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Take Frame</span>
<span class="n">Button</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">text</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">"Take Frame"</span><span class="p">,</span> <span class="n">command</span> <span class="o" style="color: #666666;">=</span> <span class="n">takeFrame</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">3</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">"WE"</span><span class="p">,</span> <span class="n">columnspan</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Delete Frame</span>
<span class="n">Button</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">text</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">"Delete Last Frame"</span><span class="p">,</span> <span class="n">command</span> <span class="o" style="color: #666666;">=</span> <span class="n">deleteFrame</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">4</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">"WE"</span><span class="p">,</span> <span class="n">columnspan</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Set FPS in</span>
<span class="n">Label</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">text</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">'Set FPS In'</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="n">W</span><span class="p">)</span>
<span class="n">Entry</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">textvariable</span> <span class="o" style="color: #666666;">=</span> <span class="n">fpsIn</span><span class="p">,</span> <span class="n">width</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">7</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'WE'</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Set FPS out</span>
<span class="n">Label</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">text</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">'Set FPS Out'</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="n">W</span><span class="p">)</span>
<span class="n">Entry</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">textvariable</span> <span class="o" style="color: #666666;">=</span> <span class="n">fpsOut</span><span class="p">,</span> <span class="n">width</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">7</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'WE'</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Create Film</span>
<span class="n">Button</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">text</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">"Create Film"</span><span class="p">,</span> <span class="n">command</span> <span class="o" style="color: #666666;">=</span> <span class="n">createFilm</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">7</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">"WE"</span><span class="p">,</span> <span class="n">columnspan</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">)</span>
<span class="n">updateGUI</span><span class="p">()</span>
<span class="n">root</span><span class="o" style="color: #666666;">.</span><span class="n">mainloop</span><span class="p">()</span></pre>
<br />
To start with there are a few libraries which you will need to access. These are always imported first into your program, as you cannot use them until they have been imported.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="kn" style="color: #007020; font-weight: bold;">from</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">Tkinter</span> <span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="kn" style="color: #007020; font-weight: bold;">from</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">ttk</span> <span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">os</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">glob</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">Image</span><span class="o" style="color: #666666;">,</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">ImageTk</span></pre>
<br />
Next we have all the function which the program calls. Before we write these, let us jump down the code a little and set out our GUI. Once the GUI is set up we can write the required functions later.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">##Setup of main GUI</span>
<span class="n">root</span> <span class="o" style="color: #666666;">=</span> <span class="n">Tk</span><span class="p">()</span>
<span class="n">root</span><span class="o" style="color: #666666;">.</span><span class="n">title</span> <span class="p">(</span><span class="s" style="color: #4070a0;">'Animation Studio'</span><span class="p">)</span>
<span class="n">root</span><span class="o" style="color: #666666;">.</span><span class="n">geometry</span><span class="p">(</span><span class="s" style="color: #4070a0;">"410x450"</span><span class="p">)</span></pre>
<br />
These lines of text set up the layout of the GUI. They help us define the name and the size of the window. The values stated as 410x450 are the width and height of our GUI. You can change these if you would like to, but I think these are good values.<br />
<br />
Now we define a frame within our GUI.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">mainframe</span> <span class="o" style="color: #666666;">=</span> <span class="n">Frame</span><span class="p">(</span><span class="n">root</span><span class="p">,</span> <span class="n">padding</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'3 3 12 12'</span><span class="p">)</span>
<span class="n">mainframe</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="n">sticky</span><span class="o" style="color: #666666;">=</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="n">W</span><span class="p">,</span><span class="n">E</span><span class="p">,</span><span class="n">S</span><span class="p">))</span>
<span class="n">mainframe</span><span class="o" style="color: #666666;">.</span><span class="n">columnconfigure</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="n">weight</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span>
<span class="n">mainframe</span><span class="o" style="color: #666666;">.</span><span class="n">rowconfigure</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="n">weight</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span></pre>
<br />
Within our window we need to have one frame. Frames can split the window into different areas. These lines of code define how this frame fits within our window.<br />
<br />
As you can see we now define a few variables.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">##Variables</span>
<span class="n">frameNumber</span> <span class="o" style="color: #666666;">=</span> <span class="n">IntVar</span><span class="p">()</span>
<span class="n">fpsIn</span> <span class="o" style="color: #666666;">=</span> <span class="n">IntVar</span><span class="p">()</span>
<span class="n">fpsOut</span> <span class="o" style="color: #666666;">=</span> <span class="n">IntVar</span><span class="p">()</span></pre>
<br />
I know from my time-lapse program that I might want to change a few parameters when I am creating my film, for example I might want to change how many of my frames I want to display every second (fpsIn), and I might want to change the frame rate the video is created at (fpsOut).<br />
<br />
The other variable I will need is to know which of the frames we are currently looking at on the GUI. We will call this variable frameNumber.<br />
<br />
Once I have created the variables, I want to assign them values.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">##Set Variables</span>
<span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="n">countFrames</span><span class="p">())</span>
<span class="n">fpsIn</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="mi" style="color: #40a070;">10</span><span class="p">)</span>
<span class="n">fpsOut</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="mi" style="color: #40a070;">24</span><span class="p">)</span></pre>
<br />
I set the value of fpsIn to be 10, and fpsOut to be 24. The software will allow you to change them later, but these are good default values for you to start with.<br />
<br />
Setting the frameNumber looks a little different. I am not setting it with a number, but a function. What is that all about? Well I think when you load the program it would be nice to set the variable frameNumber to the last frame you have taken. You can then carry on from where you left off. Therefore I will write a function called countFrames() which returns the number of frames I have taken. We will get onto writing the function for this later.<br />
<br />
Lets now look at laying out the actual GUI.<br />
<br />
Firstly we want to be able to scroll through our images. I think it would be nice to scroll through them one at a time and also jump to the first and the last frame. We have created a variable called frameNumber which holds the information about the current frame we are displaying. We should also display that number in our GUI, so we know what we are looking at.<br />
<br />
My proposal is for the buttons to use greater than or less than symbols like this < or this > to move forward or back one frame. We will also use two of them together to jump to the first or last frame like so << >>. We will also want to display a number showing which of our images we are looking at.<br />
<br />
So our buttons should look this this<br />
<br />
<< < frame number > >><br />
<br />
The code to create these 4 buttons and text entry field is as follows:<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">##Frame Select</span>
<span class="n">Button</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">text</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">"<<"</span><span class="p">,</span> <span class="n">command</span> <span class="o" style="color: #666666;">=</span> <span class="n">firstFrame</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'WE'</span><span class="p">)</span>
<span class="n">Button</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">text</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">"<"</span><span class="p">,</span> <span class="n">command</span> <span class="o" style="color: #666666;">=</span> <span class="n">prevFrame</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'WE'</span><span class="p">)</span>
<span class="n">Button</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">text</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">">"</span><span class="p">,</span> <span class="n">command</span> <span class="o" style="color: #666666;">=</span> <span class="n">nextFrame</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">4</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'WE'</span><span class="p">)</span>
<span class="n">Button</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">text</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">">>"</span><span class="p">,</span> <span class="n">command</span> <span class="o" style="color: #666666;">=</span> <span class="n">lastFrame</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'WE'</span><span class="p">)</span>
<span class="n">Entry</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">textvariable</span> <span class="o" style="color: #666666;">=</span> <span class="n">frameNumber</span><span class="p">,</span> <span class="n">width</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">7</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">3</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'WE'</span><span class="p">)</span></pre>
<br />
Here we have created 4 buttons and a text entry field. Each of the four buttons calls a different function to allow us to jump to the first/previous/next/last frame, depending upon which button we click.<br />
The last line is an entry field, which we are using to display the value stored in our variable frameNumber.<br />
As we are using the grid layout system, each of these items is positioned using the row and column values. You can see they are all on the same row, but in different columns.<br />
<br />
Below these buttons we want a button which allows us to take a frame or picture.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">##Take Frame</span>
<span class="n">Button</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">text</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">"Take Frame"</span><span class="p">,</span> <span class="n">command</span> <span class="o" style="color: #666666;">=</span> <span class="n">takeFrame</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">3</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">"WE"</span><span class="p">,</span> <span class="n">columnspan</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">)</span>
</pre>
<div>
<span class="p"><br /></span></div>
This is a button we will want to click on to take a new frame. The button is laid out as the buttons above, but has a different label "Take Frame" and calls a different function called takeFrame when clicked. The other difference is we have a columnspan value in there. This is telling our program do not constrain the button to one column. Otherwise it would be the same width as the << button, but allow it to span 5 columns. This should make the button the same size as the size of the << < frame number > >> buttons combined.<br />
<br />
We will now create a button to allow us to delete a frame.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">##Delete Frame</span>
<span class="n">Button</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">text</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">"Delete Last Frame"</span><span class="p">,</span> <span class="n">command</span> <span class="o" style="color: #666666;">=</span> <span class="n">deleteFrame</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">4</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">"WE"</span><span class="p">,</span> <span class="n">columnspan</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">)</span>
</pre>
<div>
<span class="p"><br /></span></div>
This follows the same format as the Take Frame button. Obviously it has a different title and calls a different function.<br />
<br />
Now for the values of fpsIn and fpsOut we create a text entry field to define them, and a label to explain the text entry field.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">##Set FPS in</span>
<span class="n">Label</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">text</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">'Set FPS In'</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="n">W</span><span class="p">)</span>
<span class="n">Entry</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">textvariable</span> <span class="o" style="color: #666666;">=</span> <span class="n">fpsIn</span><span class="p">,</span> <span class="n">width</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">7</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'WE'</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Set FPS out</span>
<span class="n">Label</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">text</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">'Set FPS Out'</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="n">W</span><span class="p">)</span>
<span class="n">Entry</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">textvariable</span> <span class="o" style="color: #666666;">=</span> <span class="n">fpsOut</span><span class="p">,</span> <span class="n">width</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">7</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'WE'</span><span class="p">)</span></pre>
<br />
Our final button is the button to create the film. This is what we will click on when all the images are taken and we want the film to be made.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">##Create Film</span>
<span class="n">Button</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">text</span><span class="o" style="color: #666666;">=</span><span class="s" style="color: #4070a0;">"Create Film"</span><span class="p">,</span> <span class="n">command</span> <span class="o" style="color: #666666;">=</span> <span class="n">createFilm</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">7</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">"WE"</span><span class="p">,</span> <span class="n">columnspan</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">)</span>
</pre>
<div>
<span class="p"><br /></span></div>
Again this is similar to the other buttons we have created.<br />
<br />
The next thing we need is to show the image we have taken. To show images in Tkinter we need to put them into what is called a label. However the other thing we want to do is to update the label each time we change the image. This happens quite often in our program, therefore to save us writing the same code over and over again, we will put the label command into a function which allows us to update it when we need to. We shall create the call to the function now, but we will come back to writing the function in a minute.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">updateGUI</span><span class="p">()</span></pre>
<br />
Although this function displays the image at the top of the GUI, as this function refreshes the Tkinter screen it is important that this function is called after all the other widgets, such as buttons / labels, created in the GUI. <br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">root</span><span class="o" style="color: #666666;">.</span><span class="n">mainloop</span><span class="p">()</span></pre>
<br />
Finally we finish this section with a root.mainloop() which is important to get our Tkinter program running.<br />
<br />
OK we should now have defined out GUI. However we skipped over any functions it called, so we need to go back and write those now.<br />
<br />
The functions in my program appear in an order I think they make sense to be in. However they are not in order of what was written first. I will not go through them from top to bottom, but will jump around a little. As some functions call other functions I think the order I am explaining them in will start to make some sense.<br />
<br />
First of all we have talked about a function called countFrames(). This is a function that will count the number of frames and return the total number back to us. We will use this function throughout the program, and have already called it while setting the value in our variable frameNumber.<br />
<br />
Lets look at writing a function called countFrames()<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">##Returns the number of jpg files in the directory.</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">countFrames</span><span class="p">():</span>
<span class="n">openFiles</span> <span class="o" style="color: #666666;">=</span> <span class="n">glob</span><span class="o" style="color: #666666;">.</span><span class="n">glob</span><span class="p">(</span><span class="s" style="color: #4070a0;">'image*.jpg'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="nb" style="color: #007020;">len</span><span class="p">(</span><span class="n">openFiles</span><span class="p">)</span></pre>
<br />
The first line defines the name of the function and the fact it takes no inputs.<br />
<br />
In the timelapse blog we saved our files with the file-name in the format imageXXXXXXX.jpg. Where XXXXXXX was an incremental number. We will keep the naming convention the same in this program.<br />
<br />
<br />
The next line uses a module called glob, which we imported at the top of our program. This line creates a list called openFiles. Then it stores all the file-names which start with "image" and end with ".jpg" into this list. Remember a * denotes a wildcard, so the program finds all options which fit with the * substituted for real text. This means whatever number our file has in it, this line will add it into the list.<br />
<br />
Finally we can return the length of the list, which is counting how many items are in the list. This will be the number of frames we have.<br />
<br />
We could have written this function on one line, however I think think using two lines makes it more readable.<br />
<br />
This function we have just written returns a number. This is very convenient, as when we are doing anything with the frames, such as scrolling through them it makes sense to refer to each frame by a number. A number is also very easy for Python to increase or decrease. However for each frame we also save a picture file. We spoke earlier that this file name would be in the format imageXXXXXXX.jpg. This ensures that the file names are all the same size and stay in the correct order within our folder. To turn our frame number into this format we will have to add some leading zeroes onto it, and turn it into a string (text).<br />
<br />
As an example image 1 would become image0000001.jpg, image 100 becomes image0000100.jpg etc. Seven digits in total should be more than enough for your film.<br />
<br />
We will call a function which will find the number of the frame we are in, and return the number, as a string, with the right amount of zeros in front of it.<br />
<br />
This will help us determine our file-name.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">## sets the right number of zeros for the frameNumber</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">setZero</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="nb" style="color: #007020;">str</span><span class="p">(</span><span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">())</span><span class="o" style="color: #666666;">.</span><span class="n">zfill</span><span class="p">(</span><span class="mi" style="color: #40a070;">7</span><span class="p">)</span></pre>
<br />
The first line defines the function name, as the brackets are empty there are no parameters being passed into it.<br />
The second line does 4 things.<br />
<br />
<ul>
<li>It gets the current frame number - frameNumber.get()</li>
<li>It converts the number into a string - str(frameNumber.get())</li>
<li>It adds some leading zeros so there are 7 digits. It does this with the zfill command - str(frameNumber.get()).zfill(7)</li>
<li>It returns this string back to where it was called - return str(frameNumber.get()).zfill(7)</li>
</ul>
<br />
Very easy. The key to this is using the .zfill function to add in the leading zeros.<br />
<br />
We talked previously about displaying our current image in Tkinter. Tkinter uses a Label to display images. Although we defined all other parts of the GUI earlier we said as we would have to refresh this label quite often, so it made sense to write it in a function, so we can simply call the function every time we want to refresh the image.<br />
<br />
Let us write that function now.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">##Updates the image in the GUI and refreshes</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">updateGUI</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">countFrames</span><span class="p">()</span><span class="o" style="color: #666666;">></span><span class="mi" style="color: #40a070;">0</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;"># Checks to see if there are any existing frames</span>
<span class="n">fileName</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">"image</span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">.jpg"</span><span class="o" style="color: #666666;">%</span><span class="n">setZero</span><span class="p">()</span>
<span class="n">inFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">Image</span><span class="o" style="color: #666666;">.</span><span class="n">open</span><span class="p">(</span><span class="n">fileName</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">## Resize image to suit GUI</span>
<span class="c" style="color: #60a0b0; font-style: italic;">## Was 2592 x 1944 - Divide both of these by 6</span>
<span class="n">newSizeFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">resize</span><span class="p">((</span><span class="mi" style="color: #40a070;">400</span><span class="p">,</span><span class="mi" style="color: #40a070;">300</span><span class="p">))</span>
<span class="n">displayFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">ImageTk</span><span class="o" style="color: #666666;">.</span><span class="n">PhotoImage</span><span class="p">(</span><span class="n">newSizeFile</span><span class="p">)</span><span class="c" style="color: #60a0b0; font-style: italic;">#Convert to Tkinter compatible</span>
<span class="n">Label</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">image</span><span class="o" style="color: #666666;">=</span><span class="n">displayFile</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'WE'</span><span class="p">,</span><span class="n">columnspan</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">)</span>
<span class="n">root</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span><span class="c" style="color: #60a0b0; font-style: italic;">#Refreshes</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">frameImage</span> <span class="o" style="color: #666666;">=</span> <span class="n">PhotoImage</span><span class="p">(</span><span class="nb" style="color: #007020;">file</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">"blankScreen.gif"</span><span class="p">)</span>
<span class="n">Label</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">image</span><span class="o" style="color: #666666;">=</span><span class="n">frameImage</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'WE'</span><span class="p">,</span><span class="n">columnspan</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">)</span>
<span class="n">root</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span>
<span class="c" style="color: #60a0b0; font-style: italic;">## Creates the video file.</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">createFilm</span><span class="p">():</span>
<span class="n">setfpsIn</span> <span class="o" style="color: #666666;">=</span> <span class="n">fpsIn</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">()</span>
<span class="n">setfpsOut</span> <span class="o" style="color: #666666;">=</span> <span class="n">fpsOut</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">()</span>
<span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">system</span><span class="p">(</span><span class="s" style="color: #4070a0;">"avconv -r </span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;"> -i image</span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">.jpg -r </span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;"> -vcodec libx264 -crf 20 -g 15 -vf crop=2592:1458,scale=1280:720 timelapse.mp4"</span><span class="o" style="color: #666666;">%</span><span class="p">(</span><span class="n">setfpsIn</span><span class="p">,</span><span class="s" style="color: #4070a0;">'</span><span class="si" style="color: #70a0d0; font-style: italic;">%7d</span><span class="s" style="color: #4070a0;">'</span><span class="p">,</span><span class="n">setfpsOut</span><span class="p">))</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
This is quite a large function, so I will repeat each line below so you know which line I am referring to to help save any confusion!<br />
<br />
The first line as always defines the name of the function. Nothing is being passed into this function.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">updateGUI</span><span class="p">():</span></pre>
<br />
As we are putting one of our images into the GUI we need to first of all do a check. What if there are no images already? Not having an image there will ruin our layout a little. Therefore we need a contingency for when we have not taken any images.<br />
<br />
Lets first deal with the case when there are some images. We can use our countFrames function to determine if any images have been taken. If this reveals a number greater then 0 there are some images. That countFrames() function is becoming quite useful!<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">countFrames</span><span class="p">()</span><span class="o" style="color: #666666;">></span><span class="mi" style="color: #40a070;">0</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;"># Checks to see if there are any existing frames</span></pre>
<br />
Now we want to open up the file which relates to the frame we are currently viewing. Previously we showed we can transform the number of the current frame into a string with some leading zeros already attached by running our function setZero() well we do that in the next line.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">fileName</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">"image</span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">.jpg"</span><span class="o" style="color: #666666;">%</span><span class="n">setZero</span><span class="p">()</span></pre>
<br />
This creates a variable called fileName. It populates it with the string "image%s.jpg", but the clever part of this line is it replaces the %s after image with whatever is returned from our setZero function. %s is an easy way to get different information into strings.<br />
<br />
Now we have our file name we can use Image.open to open that file.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">inFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">Image</span><span class="o" style="color: #666666;">.</span><span class="n">open</span><span class="p">(</span><span class="n">fileName</span><span class="p">)</span> </pre>
<br />
I know that the images the camera takes are 2592 x 1944 pixels. These are quite large. To make it easier to view on the screen I will resize these. By dividing 2592 by 6 and 1944 by 6 I get 400 x 300. Apart from being nice numbers and about the right size it ensures the aspect ration is kept the same i.e. the images are not stretched either horizontally or vertically.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">newSizeFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">inFile</span><span class="o" style="color: #666666;">.</span><span class="n">resize</span><span class="p">((</span><span class="mi" style="color: #40a070;">400</span><span class="p">,</span><span class="mi" style="color: #40a070;">300</span><span class="p">))</span></pre>
<br />
Tkinter cannot display .jpg images. So we have to convert our image to allow Tkinter to display it. We do this by the following command.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">displayFile</span> <span class="o" style="color: #666666;">=</span> <span class="n">ImageTk</span><span class="o" style="color: #666666;">.</span><span class="n">PhotoImage</span><span class="p">(</span><span class="n">newSizeFile</span><span class="p">)</span></pre>
<br />
Finally we get around to creating the label which we use to display files in Tkinter.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">Label</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">image</span><span class="o" style="color: #666666;">=</span><span class="n">displayFile</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'WE'</span><span class="p">,</span><span class="n">columnspan</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">)</span></pre>
<br />
We would normally have placed this line with all the other Tkinter buttons and labels. However as we want to decide when we want to update the label it was better off as a function. If we were not modifying the image we may have left it in the usual place, with all the other Tkinter widgets.<br />
<br />
Finally we refresh the window<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">root</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span><span class="c" style="color: #60a0b0; font-style: italic;">#Refreshes</span></pre>
<br />
So that covers the times when we have already taken frames. We now need to look into the times when there are no existing frames. This is likely when we are using the project for the first time and do not have existing .jpg images.<br />
<br />
If we did not load an image the positioning of our GUI would all be thrown out. Therefore if there are no images we will load one which we have pre-created.<br />
<br />
We need to start with an else statement.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span></pre>
<br />
Now we load our image, which this time is a .gif image. We don't need to do any conversion on this as Tkinter handles .gif images quite nicely. We load the file and store it in a variable called frameImage<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">frameImage</span> <span class="o" style="color: #666666;">=</span> <span class="n">PhotoImage</span><span class="p">(</span><span class="nb" style="color: #007020;">file</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">"blankScreen.gif"</span><span class="p">)</span></pre>
<br />
Now as before we create a Label to display this blank image, and then refresh the screen.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">Label</span><span class="p">(</span><span class="n">mainframe</span><span class="p">,</span> <span class="n">image</span><span class="o" style="color: #666666;">=</span><span class="n">frameImage</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">grid</span><span class="p">(</span><span class="n">column</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">row</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span><span class="p">,</span> <span class="n">sticky</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">'WE'</span><span class="p">,</span><span class="n">columnspan</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span><span class="p">)</span>
<span class="n">root</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span></pre>
<br />
And that finishes our updateGUI function. It is important that you have the <a href="https://drive.google.com/file/d/0B87aGq7vEpoFYTl6ZlAyWnBES0k/edit?usp=sharing" target="_blank">blankScreen.gif</a> image in the same folder as your Animation Studio folder, otherwise the software will not work.<br />
<br />
We should start now looking at the buttons for scrolling through the images.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">## Functions to select frames</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">firstFrame</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">countFrames</span><span class="p">()</span><span class="o" style="color: #666666;">></span><span class="mi" style="color: #40a070;">0</span><span class="p">:</span>
<span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;">#If there are any frames</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;">#Set to 0 if there are none</span>
<span class="n">updateGUI</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
The idea of this function is to go to the first frame or picture we have taken. As we have already created a variable called frameNumber, we should be able to set that to the right value, and then update our GUI to suit. Should be simple... but we have to cover all eventualities. What if we have not taken a picture? We need to ensure our program deals with that.<br />
<br />
Using an if ... else statement should be just the trick.<br />
<br />
If we have taken frames previously the number of frames will be greater than 0. Therefore frame 1 will be the first frame, so we should set the frame we want to look at as 1. If we have not taken any frames, then the first will be frame 0. We will set the variable frameNumber to suit.<br />
<br />
After naming our function the first line makes use of our frameCount function we have written earlier.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">firstFrame</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">countFrames</span><span class="p">()</span><span class="o" style="color: #666666;">></span><span class="mi" style="color: #40a070;">0</span><span class="p">:</span>
<span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;">#If there are any frames</span></pre>
</pre>
<br />
This says if the value from countFrames is greater than 0, which should be the case if any frames have been taken, then we can set the frame number to 1. This should be the first frame we have taken.<br />
<br />
If the else statement comes into play<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;">#Set to 0 if there are none</span></pre>
<br />
Then there are no frames which have been taken. We should set the frame number to 0.<br />
<br />
Now we make use of our great updateGUI() function which refreshes the screen to reflect the frame number we are currently on.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">updateGUI</span><span class="p">()</span>
</pre>
Finally we return None.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;">
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
The next function helps us navigate to the last frame we have taken.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">lastFrame</span><span class="p">():</span>
<span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="n">countFrames</span><span class="p">())</span>
<span class="n">updateGUI</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
Firstly we define the function name.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">lastFrame</span><span class="p">():</span></pre>
<br />
Now we can set the frameNumber to the value returned from the function countFrames(). This should return the number of the last frame.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="n">countFrames</span><span class="p">())</span></pre>
<br />
We just need to update our GUI to reflect this change.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">updateGUI</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
Finally we return None.<br />
<br />
The next function is the next frame function. We need to think about this one a little more. If we are at the last frame and try to move along, our program will likely crash. Therefore we should only allow our program to move to the next frame if the frame we are currently on is less than the total number of frames.<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">nextFrame</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">()</span> <span class="o" style="color: #666666;"><</span> <span class="p">(</span><span class="n">countFrames</span><span class="p">()):</span>
<span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">()</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span>
<span class="n">updateGUI</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
So after defining the function name.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">nextFrame</span><span class="p">():</span></pre>
<br />
We can check to see if the current frame is not more than the total frames we have taken.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">()</span> <span class="o" style="color: #666666;"><</span> <span class="p">(</span><span class="n">countFrames</span><span class="p">()):</span></pre>
<br />
If we have not gone over the total number of frames, then we can increase our current frame number by one. We do this by getting the current frame number, adding one to it and then setting this as our frameNumber. This is all done in a single line.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">()</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span></pre>
<br />
Again we update the GUI and return None<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">updateGUI</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
The previous frame function is similar to the next frame function.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">prevFrame</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">()</span> <span class="o" style="color: #666666;">></span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">()</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span>
<span class="n">updateGUI</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
However this time we check to ensure our current frame is greater than 1. We should only allow the user to reduce the frame count if this is the case.<br />
<br />
We do that check by using frameNumber.get()<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">()</span> <span class="o" style="color: #666666;">></span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span></pre>
<br />
We then use the same method we used to increase our frame number by 1 by reducing it by one.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">()</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span></pre>
<br />
Finally we again updateGUI() and then return None.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">updateGUI</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
The next thing we need to do is create the function which allows us to take frames.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">takeFrame</span><span class="p">():</span>
<span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="n">countFrames</span><span class="p">()</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span>
<span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">system</span><span class="p">(</span><span class="s" style="color: #4070a0;">"raspistill -o image</span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">.jpg"</span><span class="o" style="color: #666666;">%</span><span class="p">(</span><span class="n">setZero</span><span class="p">()))</span>
<span class="n">updateGUI</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
No matter which frame we are looking at we don't want to overwrite a frame. We want to save the frame we take as the number AFTER the total number of frames, which is a number not currently used.<br />
<br />
Therefore the first thing we do is to set the variable frameNumber to one after the total number of frames.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="n">countFrames</span><span class="p">()</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span> </pre>
<br />
We take the image in a very similar way we did in the timelapse program we created.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">system</span><span class="p">(</span><span class="s" style="color: #4070a0;">"raspistill -o image</span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">.jpg"</span><span class="o" style="color: #666666;">%</span><span class="p">(</span><span class="n">setZero</span><span class="p">()))</span></pre>
<br />
The only difference is we use the setZero function to convert the frame number to text to be inserted in the file name.<br />
<br />
Finally we update the GUI<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">updateGUI</span><span class="p">()</span>
</pre>
and return None<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
The next function which we need to write is to delete frames. We could program it to delete any frame but there are pitfalls to this, as we would have to replace these deleted frames, either taking a new frame or by reducing the number on all the remaining frames after the one we have deleted. This could get complicated. An easier option would be to allow us to delete the last frame. For the purpose of this project that's what we shall do.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">##Deletes the last stored frame</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">deleteFrame</span><span class="p">():</span>
<span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="n">countFrames</span><span class="p">())</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">countFrames</span><span class="p">()</span> <span class="o" style="color: #666666;">></span> <span class="mi" style="color: #40a070;">0</span><span class="p">:</span>
<span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">remove</span><span class="p">(</span><span class="s" style="color: #4070a0;">'image</span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">.jpg'</span><span class="o" style="color: #666666;">%</span><span class="n">setZero</span><span class="p">())</span>
<span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="n">countFrames</span><span class="p">())</span>
<span class="n">updateGUI</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
First we will define the function name.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">deleteFrame</span><span class="p">():</span> </pre>
<br />
We will set the frame to the last frame, by calling the countFrames function.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="n">countFrames</span><span class="p">())</span></pre>
<br />
Next we check there are some frames. We don't want to try to delete any frames which are not there.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">countFrames</span><span class="p">()</span> <span class="o" style="color: #666666;">></span> <span class="mi" style="color: #40a070;">0</span><span class="p">:</span></pre>
<br />
We will use the os.remove function to remove the frame we are currently on, which is of course the last frame, we have taken.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">remove</span><span class="p">(</span><span class="s" style="color: #4070a0;">'image</span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">.jpg'</span><span class="o" style="color: #666666;">%</span><span class="n">setZero</span><span class="p">())</span></pre>
<br />
As we were looking at the last frame, which we just deleted, we should recount the frames and set the current frame to the last frame. This will avoid the program trying to update to a frame which no longer exists! Always likely to cause the software to crash!<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">frameNumber</span><span class="o" style="color: #666666;">.</span><span class="n">set</span><span class="p">(</span><span class="n">countFrames</span><span class="p">())</span></pre>
<br />
Finally update the GUI then return None<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">updateGUI</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
The final function we have to write is the function to create the film we have been taking.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">## Creates the video file.</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">createFilm</span><span class="p">():</span>
<span class="n">setfpsIn</span> <span class="o" style="color: #666666;">=</span> <span class="n">fpsIn</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">()</span>
<span class="n">setfpsOut</span> <span class="o" style="color: #666666;">=</span> <span class="n">fpsOut</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">()</span>
<span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">system</span><span class="p">(</span><span class="s" style="color: #4070a0;">"avconv -r </span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;"> -i image</span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">.jpg -r </span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;"> -vcodec libx264 -crf 20 -g 15 -vf crop=2592:1458,scale=1280:720 timelapse.mp4"</span><span class="o" style="color: #666666;">%</span><span class="p">(</span><span class="n">setfpsIn</span><span class="p">,</span><span class="s" style="color: #4070a0;">'</span><span class="si" style="color: #70a0d0; font-style: italic;">%7d</span><span class="s" style="color: #4070a0;">'</span><span class="p">,</span><span class="n">setfpsOut</span><span class="p">))</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
The first two lines ensures we get the values from our variables for fpsIn and fpsOut.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">setfpsIn</span> <span class="o" style="color: #666666;">=</span> <span class="n">fpsIn</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">()</span>
<span class="n">setfpsOut</span> <span class="o" style="color: #666666;">=</span> <span class="n">fpsOut</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">()</span></pre>
<br />
Now we create the video using the avconv tool.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">system</span><span class="p">(</span><span class="s" style="color: #4070a0;">"avconv -r </span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;"> -i image</span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">.jpg -r </span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;"> -vcodec libx264 -crf 20 -g 15 -vf crop=2592:1458,scale=1280:720 timelapse.mp4"</span><span class="o" style="color: #666666;">%</span><span class="p">(</span><span class="n">setfpsIn</span><span class="p">,</span><span class="s" style="color: #4070a0;">'</span><span class="si" style="color: #70a0d0; font-style: italic;">%7d</span><span class="s" style="color: #4070a0;">'</span><span class="p">,</span><span class="n">setfpsOut</span><span class="p">))</span></pre>
<br />
There is a little more about this on my <a href="http://trevorappleton.blogspot.co.uk/2013/11/creating-time-lapse-camera-with.html" target="_blank">timelapse blog</a>. This takes all the images you have created and turns them into a video.<br />
<br />
Finally we return None<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
And that should finalise the program.<br />
<br />
All that is required is to now run the program by pressing F5. As a reminder remember to have the blankScreen.gif image in the same location as your program, as this is where your program will look for it.<br />
<br />
<a href="https://drive.google.com/file/d/0B87aGq7vEpoFYTl6ZlAyWnBES0k/edit?usp=sharing">blankScreen.gif</a><br />
<br />
If you would like to download the source code, you can do so by clicking on the link below.<br />
<br />
<a href="https://drive.google.com/file/d/0B87aGq7vEpoFTkR6RmJDaGVqN2M/edit?usp=sharing" target="_blank">Animation Studio Source Code</a><br />
<br />
When you run the program you should see a user interface like this.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhw419L3LAZE9CW7v-1B4DgtSoM1KBh1s1eb6qz5SYAHGBJH3UPP7iou6q1GvWxGlHrF7Wj6Yb5JEBfI5A-J89nvfkeMajY9dFvODhYu3HQ83gEsidsM6mZnDO2LD-bJ0ptWTe_caka3yQ/s1600/AnimationStudio.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhw419L3LAZE9CW7v-1B4DgtSoM1KBh1s1eb6qz5SYAHGBJH3UPP7iou6q1GvWxGlHrF7Wj6Yb5JEBfI5A-J89nvfkeMajY9dFvODhYu3HQ83gEsidsM6mZnDO2LD-bJ0ptWTe_caka3yQ/s320/AnimationStudio.png" height="320" width="279" /></a></div>
<br />
<br />
I hope you have enjoyed this blog post, I certainly had fun writing it! I would very much like to see some of your animation movies you create with this!<br />
<br />
<br />
<br />
<br />Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com51tag:blogger.com,1999:blog-8250429656532783188.post-90978665496077580892013-11-26T12:37:00.001+00:002014-04-28T11:01:59.062+01:00Creating a Time-Lapse Camera with the Raspberry Pi and PythonAfter the success<a href="http://trevorappleton.blogspot.co.uk/2013/11/python-getting-started-with-opencv.html" target="_blank"> using openCV with the Raspberry Pi camera</a> to determine the positions of circles in an image, I thought it would be nice to explore more uses of the camera. My inspiration came from a chat with a consultancy I visited. They were in the middle of a large expansion of their site, and were having a lot of building work carried out. To document the building work they had set up a Raspberry Pi with a camera to capture the work and to create a time-lapse video of it.<br />
<br />
How much fun does that sound?<br />
<br />
My mind was made up - I decided to write a time-lapse video program using Python.<br />
<br />
I knew taking the images would be quite simple, but the conversion into video would be more tricky.<br />
<br />
My first thought was to make use of the openCV libraries again to turn the images into video. However while I believe this is possible, I really struggled to find the solution. Documentation for openCV is very much geared to C++ and not Python.<br />
<br />
My second attempt was to use ffmpeg. Some googling had shown this was a nice solution for the conversion. However after installing and running it I got a message saying<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3Eg9QkfzASFNd1OpvKl7nJ1olxF6tzpb49G-6sOygFDbWrjNZgAmBQJP8HiUarn8Xrt745qY6S26FFiPvMn-Z-gIUIXy0vB9BgO197YP5R_ggg82vJIAXm_LRpub3Vpm8cYI0P4PLQMg/s1600/ffmpegErrorMessage.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="110" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3Eg9QkfzASFNd1OpvKl7nJ1olxF6tzpb49G-6sOygFDbWrjNZgAmBQJP8HiUarn8Xrt745qY6S26FFiPvMn-Z-gIUIXy0vB9BgO197YP5R_ggg82vJIAXm_LRpub3Vpm8cYI0P4PLQMg/s400/ffmpegErrorMessage.PNG" width="400" /></a></div>
<br />
More googling told me I should install ffmpeg from binaries, which I am more than comfortable to do, but it does add complexity into my blog post...<br />
<br />
Wait a minute! What was that last sentence on the error message? "Please use avconv instead"<br />
<br />
More googling required!<br />
<br />
It turns out that avconv does exactly what I need it to do. It converts a pile of images into a video. There are a lot of examples on the web explaining what settings you should use with avconv. However while the avconv website has a lot of information on there I found the best explanation came from the excellent Raspberry Pi Spy website, whose post was also explaining how to create a time-lapse video. Its worth having a look at his page, as he explains how to take images and create video using only the command line.<br />
<br />
<a href="http://www.raspberrypi-spy.co.uk/2013/05/creating-timelapse-videos-with-the-raspberry-pi-camera/">http://www.raspberrypi-spy.co.uk/2013/05/creating-timelapse-videos-with-the-raspberry-pi-camera/</a><br />
<br />
Right so how do we write a Python program to create a time-lapse video?<br />
<br />
The first thing you need to do is to install libav-tools.<br />
<br />
Type the following into a command line.<br />
<br />
sudo apt-get install -y libav-tools<br />
<br />
Here is the full program, have a read through it and see if you can figure out what each line is doing. I will then explain each line in more detail.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">os</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">time</span>
<span class="n">FRAMES</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1000</span>
<span class="n">FPS_IN</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">10</span>
<span class="n">FPS_OUT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">24</span>
<span class="n">TIMEBETWEEN</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">6</span>
<span class="n">FILMLENGTH</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">FRAMES</span> <span class="o" style="color: #666666;">/</span> <span class="n">FPS_IN</span><span class="p">)</span>
<span class="n">frameCount</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="k" style="color: #007020; font-weight: bold;">while</span> <span class="n">frameCount</span> <span class="o" style="color: #666666;"><</span> <span class="n">FRAMES</span><span class="p">:</span>
<span class="n">imageNumber</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">str</span><span class="p">(</span><span class="n">frameCount</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">zfill</span><span class="p">(</span><span class="mi" style="color: #40a070;">7</span><span class="p">)</span>
<span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">system</span><span class="p">(</span><span class="s" style="color: #4070a0;">"raspistill -o image</span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">.jpg"</span><span class="o" style="color: #666666;">%</span><span class="p">(</span><span class="n">imageNumber</span><span class="p">))</span>
<span class="n">frameCount</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">time</span><span class="o" style="color: #666666;">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">TIMEBETWEEN</span> <span class="o" style="color: #666666;">-</span> <span class="mi" style="color: #40a070;">6</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;">#Takes roughly 6 seconds to take a picture</span>
<span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">system</span><span class="p">(</span><span class="s" style="color: #4070a0;">"avconv -r </span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;"> -i image</span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">.jpg -r </span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;"> -vcodec libx264 -crf 20 -g 15 -vf crop=2592:1458,scale=1280:720 timelapse.mp4"</span><span class="o" style="color: #666666;">%</span><span class="p">(</span><span class="n">FPS_IN</span><span class="p">,</span><span class="s" style="color: #4070a0;">'</span><span class="si" style="color: #70a0d0; font-style: italic;">%7d</span><span class="s" style="color: #4070a0;">'</span><span class="p">,</span><span class="n">FPS_OUT</span><span class="p">))</span></pre>
<br />
To begin with we need to import two libraries, os which will allow us to interact with the command line, and time to enable us to set the time between frames.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">os</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">time</span></pre>
<br />
Now we will set some global variables. The nice thing about global variables is that you can change a variable that appears all through your program by just changing it in one location. Global variables also make your code more readable, as words explain what the variable is better than a number appearing thorughout your code. It also makes for code which is easier to modify as you know that all your global variables are specified at the top of your code.<br />
<br />
We will set 5 global variables.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">FRAMES</span> <span class="o" style="color: #666666;">=</span> <span style="color: #40a070;">1000</span>
<span class="n">FPS_IN</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">10</span>
<span class="n">FPS_OUT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">24</span>
<span class="n">TIMEBETWEEN</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">6</span>
<span class="n">FILMLENGTH</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">float</span><span class="p">(</span><span class="n">FRAMES</span> <span class="o" style="color: #666666;">/</span> <span class="n">FPS_IN</span><span class="p">)</span></pre>
<br />
FRAMES sets the number of frames or images you will take and add to your video.<br />
FPS_IN sets the number of the Frames Per Second (FPS) that go into the video. So if you want 10 of your frames to be used per second put the value to 10.<br />
FPS_OUT sets the Frames Per Second of the video created. i.e. creates a video running at 24 Frames Per Second. If FPS_IN is less that FPS_OUT some FPS_IN frames will be used several times to bring the number up to FPS_OUT. Setting this value to 24 is a good value for digital video.<br />
TIMEBETWEEN states the time (in seconds) between the frames that you are shooting with your camera. The Raspberry Pi camera takes roughly 6 seconds to take an image, so 6 seconds is the shortest time between shots. <br />
FILMLENGTH works out how long your film will be in seconds. If you want to know this value, then you get your program to print it using the following line.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">FILMLENGTH</span></pre>
<br />
I am not going to print this out, but I do use it as a reminder of how long the film I am making will be.<br />
<br />
Now we have set up all our variables we can get down to business. We want to take images every so often and save them as files. We will want to keep track of how many images we have taken so we know when to stop. So lets create a variable to do that.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">frameCount</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span></pre>
<br />
The next thing we will do is enter a WHILE loop. A while loop keeps going WHILE something is true<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">while</span> <span class="n">frameCount</span> <span class="o" style="color: #666666;"><</span> <span class="n">FRAMES</span><span class="p">:</span></pre>
<br />
So while our number in frameCount is less than ( < ) the number we have stored in FRAMES we will run through the next 4 lines of code.<br />
<br />
We will create a name for the pictures we want to save.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">imageNumber</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">str</span><span class="p">(</span><span class="n">frameCount</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">zfill</span><span class="p">(</span><span class="mi" style="color: #40a070;">7</span><span class="p">)</span></pre>
The reason we want to do this is we want the files to be stored with incremental numbers. This line is quite clever (I think!)<br />
<br />
It says we will create a variable called imageNumber. In that variable we will store a string of the value in frameCount. Remember a string is classed as text and not a number. Then using the .zfill(7) command we will ensure that the string has 7 digits by filling all preceding digits with a zero if there are not enough numbers. Some examples are:<br />
<br />
'1' becomes '0000001'<br />
'123456' becomes '0123456'<br />
<br />
It's not a tool you use very often, but if you want something to be a certain amount of characters it's very useful!<br />
<br />
Now we have the name of the image file we are going to create, lets take the image! We are going to use the line you can type into the shell command to take the image.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">system</span><span class="p">(</span><span class="s" style="color: #4070a0;">"raspistill -o image</span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">.jpg"</span><span class="o" style="color: #666666;">%</span><span class="p">(</span><span class="n">imageNumber</span><span class="p">))</span></pre>
<br />
What does this line mean? Well the line for taking pictures with the Raspberry Pi camera and storing it as image.jpg is<br />
<br />
raspistill -o image.jpg<br />
<br />
but this needs to be typed into the command line. Well os.system allows you to access the command line.<br />
<br />
You will notice there is a %s in there with %(imageNumber) after the text.<br />
<br />
This says, take whatever is in the value imageNumber and put it in place of the %s. So if imageNumber was 0000001 our file would be called image0000001.jpg.<br />
<br />
This is a great technique of easily modifying what is in a string.<br />
<br />
As we want our number to increase each time we go through the while loop let us now increase frameCount.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">frameCount</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span></pre>
<br />
With imageNumber being made up of frameCount and some leading zeros, each time we run through the while loop we will get a different number as frameCount is increased each time.<br />
<br />
Finally we want to be able to vary the time between taking each frame. This allows us to take our images a set distance apart. It takes roughly 6 seconds to take a picture with the Raspberry Pi camera.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">time</span><span class="o" style="color: #666666;">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">TIMEBETWEEN</span> <span class="o" style="color: #666666;">-</span> <span class="mi" style="color: #40a070;">6</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;">#Takes roughly 6 seconds to take a picture</span></pre>
<br class="Apple-interchange-newline" />
Therefore the minimum time between each frame is 6 seconds. If we want the camera to wait 10 seconds per image, as it takes 6 seconds to take a picture we only want to sleep between frames for 4 seconds. Therefore we tell the program to sleep for a period of TIMEBETWEEN - 6.<br />
<br />
This brings us to the last line of the code. As I mentioned earlier I found the Raspberry Pi Spy website to have the best details on how to use avconv. They suggest typing the following line into the command line to create video from the images. They also explain why.<br />
<br />
avconv -r 10 -i image%4d.jpg -r 10 -vcodec libx264 -crf 20 -g 15 -vf crop=2592:1458,scale=1280:720 timelapse.mp4<br />
<br />
I have modified this line slightly to make it a little more suitable for our program. I want to be able to set some of the variables using our global variables. Therefore I have changed the line slightly to this.<br />
<pre style="border: none; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">system</span><span class="p">(</span><span class="s" style="color: #4070a0;">"avconv -r </span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;"> -i image</span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">.jpg -r </span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;"> -vcodec libx264 -crf 20 -g 15 -vf crop=2592:1458,scale=1280:720 timelapse.mp4"</span><span class="o" style="color: #666666;">%</span><span class="p">(</span><span class="n">FPS_IN</span><span class="p">,</span><span class="s" style="color: #4070a0;">'</span><span class="si" style="color: #70a0d0; font-style: italic;">%7d</span><span class="s" style="color: #4070a0;">'</span><span class="p">,</span><span class="n">FPS_OUT</span><span class="p">))</span></pre>
</pre>
We already know why we use the os.system command, as this allows us access to the command line. I have also added in a few %s commands to switch in our global variables. This is using the same technique we used on the line where we took the picture. The difference is there are three variables we are switching in.<br />
<br />
Let us look at he code inside the os.system brackets.<br />
<br />
Most of the code is the same as from the Raspberry Pi Spy webpage, but there are a few differences.<br />
<br />
<br />
<ul>
<li>-r %s this sets the frame rate for the number of our frames we want to use in the video per second. The %s calls the first item in the list <span class="o" style="color: #666666; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">%</span><span class="p" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">(</span><span class="n" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">FPS_IN</span><span class="p" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">,</span><span class="s" style="color: #4070a0; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">'</span><span class="si" style="color: #70a0d0; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; font-style: italic;">%7d</span><span class="s" style="color: #4070a0; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">'</span><span class="p" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">,</span><span class="n" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">FPS_OUT</span><span class="p" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">),</span><span style="font-family: inherit;"><span class="p" style="font-size: 13px;"> </span><span class="p">which is FPS_IN, one of our global variables. </span></span></li>
<li><span style="font-family: inherit;">-i image%s.jpg determines the name of the images we want to load into our video. Again we call something within our list </span> <span class="o" style="color: #666666; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">%</span><span class="p" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">(</span><span class="n" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">FPS_IN</span><span class="p" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">,</span><span class="s" style="color: #4070a0; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">'</span><span class="si" style="color: #70a0d0; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; font-style: italic;">%7d</span><span class="s" style="color: #4070a0; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">'</span><span class="p" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">,</span><span class="n" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">FPS_OUT</span><span class="p" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">)</span><span class="p" style="font-family: inherit;">, this time the second item. What does %7d do? Remember this is being run in the command line, so it's not a python command. The %7d iterates through 7 digit numbers. This is neat as we created our image files with 7 digit numbers. So it is iterating through the images we created. </span></li>
<li><span style="font-family: inherit;">-r %s as for the first -r %s in this line this sets the number of FPS. However we call the FPS_OUT variable and insert this and not the FPS_IN variable. This will create a video of so many Frames Per Second depending on the value of FPS_OUT. If you are unsure 24 is a good default number to use.</span></li>
</ul>
<br />
<span class="p" style="font-family: inherit;"><br /></span>
<span class="p" style="font-family: inherit;">All that is left now is to run your program. One word of warning is that avconv is not quick on the Raspberry Pi. 1000 Frames took 3.5 hours to turn into a video. However it's not a huge problem, you just leave it running over night!</span><br />
<br />
I hope you found this tutorial interesting and I look forward to seeing some of your time-lapse videos!Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com14tag:blogger.com,1999:blog-8250429656532783188.post-24943055519045500082013-11-01T13:40:00.003+00:002013-11-26T22:30:48.095+00:00Python - Getting started with OpenCVA couple of years ago a colleague of mine created a program to ensure that an item I had designed was calibrated properly. The program used a webcam to check a bracket was in the right position and reported back a pass or a fail. I did not know much about the workings of the program, other than it used something called a "Hough Transform". As a non-programmer at the time, I was impressed. I thought this was a very cool program.<br />
<br />
A few weeks ago I needed to do something similar. I wanted to check that I could repeatedly position an item in the same location. My colleague has long left the company, so I thought it might be a good opportunity to see if I could write a similar program in Python. It was also an opportunity to finally put my Raspberry Pi camera module to good use.<br />
<br />
If you don't have a Raspberry Pi camera, don't worry, you can test this out on pictures taken with a normal camera. I will also supply you some images later on for you to use. One of these I took with a camera phone, so you could do the same if you want to practice.<br />
<br />
My starting point for this program was I knew that my colleague had used a Hough Transform, and that there were some good vision libraries available called openCV. I also knew these were available on Python. My program uses a Hough Circle Transform as opposed to a Hough Line Transform.<br />
<br />
The objective I was trying to achieve was to be able to check the position of an item and to determine its offset in x, y and any rotation (theta) of the object.<br />
<br />
I knew I was able to add some fiducial to the item, so opted for two circles. To make my circles a universal size, rather than drawing around coins to make my circles, I used the inside of a CD as a template. However I will show you how to tweak your program for other circles later!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghYGE3vrURARMlY6dCWqrHl8Cgiy6YoN0FHoDHFBhljY0Vszmy6mBvCX7n5_nibDk6NPXMatKqt8ERA-Ho7CstPi0UGmi96tjpjTmEgQsThrLdbavT3f4j5IoMa60tGQPxbd2y2em34ag/s1600/HoughCircles.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="135" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghYGE3vrURARMlY6dCWqrHl8Cgiy6YoN0FHoDHFBhljY0Vszmy6mBvCX7n5_nibDk6NPXMatKqt8ERA-Ho7CstPi0UGmi96tjpjTmEgQsThrLdbavT3f4j5IoMa60tGQPxbd2y2em34ag/s400/HoughCircles.PNG" width="400" /></a></div>
<br />
<br />
The first thing you need to do it to install the openCv libraries onto your Raspberry Pi.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;">sudo apt-get install libopencv-dev python-opencv</pre>
<br />
To begin with I struggled to find information to get me started, and there seemed to be a lot of confusing information scattered about the web. What I did find out which makes things a little easier to understand is that openCV has released two types of Python interface called cv and cv2. If you are googling for further information it's worth keeping this in mind. We are going to use cv2 in this tutorial.<br />
<br />
First of all here is my code and then we will analyse it line by line.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">os</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">cv2</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">math</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Resize with resize command</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">resizeImage</span><span class="p">(</span><span class="n">img</span><span class="p">):</span>
<span class="n">dst</span> <span class="o" style="color: #666666;">=</span> <span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">resize</span><span class="p">(</span><span class="n">img</span><span class="p">,</span><span class="bp" style="color: #007020;">None</span><span class="p">,</span> <span class="n">fx</span><span class="o" style="color: #666666;">=</span><span class="mf" style="color: #40a070;">0.25</span><span class="p">,</span> <span class="n">fy</span><span class="o" style="color: #666666;">=</span><span class="mf" style="color: #40a070;">0.25</span><span class="p">,</span> <span class="n">interpolation</span> <span class="o" style="color: #666666;">=</span> <span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">INTER_LINEAR</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">dst</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Take image with Raspberry Pi camera</span>
<span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">system</span><span class="p">(</span><span class="s" style="color: #4070a0;">"raspistill -o image.jpg"</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Load image</span>
<span class="n">img</span> <span class="o" style="color: #666666;">=</span> <span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">imread</span><span class="p">(</span><span class="s" style="color: #4070a0;">"/home/pi/Desktop/image.jpg"</span><span class="p">)</span>
<span class="n">grey</span> <span class="o" style="color: #666666;">=</span> <span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">imread</span><span class="p">(</span><span class="s" style="color: #4070a0;">"/home/pi/Desktop/image.jpg"</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;">#0 for grayscale</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Run Threshold on image to make it black and white</span>
<span class="n">ret</span><span class="p">,</span> <span class="n">thresh</span> <span class="o" style="color: #666666;">=</span> <span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">threshold</span><span class="p">(</span><span class="n">grey</span><span class="p">,</span><span class="mi" style="color: #40a070;">50</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">THRESH_BINARY</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Use houghcircles to determine centre of circle</span>
<span class="n">circles</span> <span class="o" style="color: #666666;">=</span> <span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">HoughCircles</span><span class="p">(</span><span class="n">thresh</span><span class="p">,</span><span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">cv</span><span class="o" style="color: #666666;">.</span><span class="n">CV_HOUGH_GRADIENT</span><span class="p">,</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">75</span><span class="p">,</span><span class="n">param1</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">50</span><span class="p">,</span><span class="n">param2</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">13</span><span class="p">,</span><span class="n">minRadius</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="n">maxRadius</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">175</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">i</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">circles</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,:]:</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#draw the outer circle</span>
<span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">circle</span><span class="p">(</span><span class="n">img</span><span class="p">,(</span><span class="n">i</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">],</span><span class="n">i</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]),</span><span class="n">i</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">],(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">),</span><span class="mi" style="color: #40a070;">2</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#draw the centre of the circle</span>
<span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">circle</span><span class="p">(</span><span class="n">img</span><span class="p">,(</span><span class="n">i</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">],</span><span class="n">i</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]),</span><span class="mi" style="color: #40a070;">2</span><span class="p">,(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">),</span><span class="mi" style="color: #40a070;">3</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Determine co-ordinates for centre of circle</span>
<span class="n">x1</span> <span class="o" style="color: #666666;">=</span> <span class="n">circles</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">][</span><span class="mi" style="color: #40a070;">0</span><span class="p">][</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span>
<span class="n">y1</span> <span class="o" style="color: #666666;">=</span> <span class="n">circles</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">][</span><span class="mi" style="color: #40a070;">0</span><span class="p">][</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span>
<span class="n">x2</span> <span class="o" style="color: #666666;">=</span> <span class="n">circles</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">][</span><span class="mi" style="color: #40a070;">1</span><span class="p">][</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span>
<span class="n">y2</span> <span class="o" style="color: #666666;">=</span> <span class="n">circles</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">][</span><span class="mi" style="color: #40a070;">1</span><span class="p">][</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Angle betwen two circles</span>
<span class="n">theta</span> <span class="o" style="color: #666666;">=</span> <span class="n">math</span><span class="o" style="color: #666666;">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">math</span><span class="o" style="color: #666666;">.</span><span class="n">atan</span><span class="p">((</span><span class="n">y2</span><span class="o" style="color: #666666;">-</span><span class="n">y1</span><span class="p">)</span><span class="o" style="color: #666666;">/</span><span class="p">(</span><span class="n">x2</span><span class="o" style="color: #666666;">-</span><span class="n">x1</span><span class="p">)))</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##print information</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="s" style="color: #4070a0;">"x1 = "</span><span class="p">,</span><span class="n">x1</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="s" style="color: #4070a0;">"y1 = "</span><span class="p">,</span><span class="n">y1</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="s" style="color: #4070a0;">"x2 = "</span><span class="p">,</span><span class="n">x2</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="s" style="color: #4070a0;">"y2 = "</span><span class="p">,</span><span class="n">y2</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">theta</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">circles</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Resize image</span>
<span class="n">img</span> <span class="o" style="color: #666666;">=</span> <span class="n">resizeImage</span><span class="p">(</span><span class="n">img</span><span class="p">)</span>
<span class="n">thresh</span> <span class="o" style="color: #666666;">=</span> <span class="n">resizeImage</span><span class="p">(</span><span class="n">thresh</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Show Images </span>
<span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">imshow</span><span class="p">(</span><span class="s" style="color: #4070a0;">"thresh"</span><span class="p">,</span><span class="n">thresh</span><span class="p">)</span>
<span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">imshow</span><span class="p">(</span><span class="s" style="color: #4070a0;">"img"</span><span class="p">,</span><span class="n">img</span><span class="p">)</span>
<span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">waitKey</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">)</span></pre>
<br />
First we import 3 modules - os, cv2 and math.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">os</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">cv2</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">math</span></pre>
<br />
Now we create a function to resize images. Although we do our analysis on the full image, we will make the images smaller before we display them on the screen.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">##Resize with resize command</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">resizeImage</span><span class="p">(</span><span class="n">img</span><span class="p">):</span>
<span class="n">dst</span> <span class="o" style="color: #666666;">=</span> <span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">resize</span><span class="p">(</span><span class="n">img</span><span class="p">,</span><span class="bp" style="color: #007020;">None</span><span class="p">,</span> <span class="n">fx</span><span class="o" style="color: #666666;">=</span><span class="mf" style="color: #40a070;">0.25</span><span class="p">,</span> <span class="n">fy</span><span class="o" style="color: #666666;">=</span><span class="mf" style="color: #40a070;">0.25</span><span class="p">,</span> <span class="n">interpolation</span> <span class="o" style="color: #666666;">=</span> <span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">INTER_LINEAR</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">dst</span>
</pre>
<div>
<br /></div>
There is a more in-depth explanation of the resize function on the geometric image transformations help page in the openCV documentation.<br />
<br />
<a href="http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html">http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html</a><br />
<br />
However the important things to note are:<br />
<ul>
<li>img is the image we want to resize.</li>
<li>fx=0.25 and fy=0.25 are the factors that x and y are multiplied by. 0.25 makes the image 1/4 size.</li>
</ul>
<br />
Next we take an image using the Raspberry Pi camera.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">##Take image with Raspberry Pi camera</span>
<span class="n">os</span><span class="o" style="color: #666666;">.</span><span class="n">system</span><span class="p">(</span><span class="s" style="color: #4070a0;">"raspistill -o image.jpg"</span><span class="p">)</span></pre>
<br />
os.system allows us to input a command into the command line. We know from the camera documentation that "raspistill -o image.jpg" will take an image with the camera and store it as image.jpg.<br />
<br />
Now we load the image twice into our program. The first time as a colour image, the second as a grey-scale image.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">##Load image</span>
<span class="n">img</span> <span class="o" style="color: #666666;">=</span> <span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">imread</span><span class="p">(</span><span class="s" style="color: #4070a0;">"/home/pi/Desktop/image.jpg"</span><span class="p">)</span>
<span class="n">grey</span> <span class="o" style="color: #666666;">=</span> <span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">imread</span><span class="p">(</span><span class="s" style="color: #4070a0;">"/home/pi/Desktop/image.jpg"</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;">#0 for grayscale</span></pre>
<br />
We then use cv2.threshold to turn our image into black and white.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">##Run Threshold on image to make it black and white</span>
<span class="n">ret</span><span class="p">,</span> <span class="n">thresh</span> <span class="o" style="color: #666666;">=</span> <span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">threshold</span><span class="p">(</span><span class="n">grey</span><span class="p">,</span><span class="mi" style="color: #40a070;">50</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">THRESH_BINARY</span><span class="p">)</span></pre>
<br />
There is more information about the threshold function on the transformations help page on the openCV documentation.<br />
<br />
<a href="http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html">http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html</a><br />
<br />
The important parts of the code are:<br />
<ul>
<li>grey - the image we are converting.</li>
<li>50 - is the threshold value. This is between 0 and 255. 0 is white and 255 is black. You may need to modify this value depending on your lighting conditions.</li>
<li>255 - If a pixel is above the threshold value, in our case 50, we will make it 255 (black). Else is it 0 (white)</li>
</ul>
On this black and white image we now run hough circles.<br />
<br />
This line in the code carries out the HoughCircle transform. This is the most important line in the code, and the one you are most likely to have to modify to suit your image.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">##Use houghcircles to determine centre of circle</span>
<span class="n">circles</span> <span class="o" style="color: #666666;">=</span> <span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">HoughCircles</span><span class="p">(</span><span class="n">thresh</span><span class="p">,</span><span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">cv</span><span class="o" style="color: #666666;">.</span><span class="n">CV_HOUGH_GRADIENT</span><span class="p">,</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">75</span><span class="p">,</span><span class="n">param1</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">50</span><span class="p">,</span><span class="n">param2</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">13</span><span class="p">,</span><span class="n">minRadius</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="n">maxRadius</span><span class="o" style="color: #666666;">=</span><span class="mi" style="color: #40a070;">175</span><span class="p">)</span></pre>
<br />
<ul>
<li>thresh - refers to the fact we are carrying out the hough transform on the black and white image.</li>
<li>75 - refers to the minimum distance allowed between circles. If you are getting too many circles close together you may want to increase this and vice versa.</li>
<li>Param1 = 50. This is one of the parameters which determines where the circles are, you can play around with this figure if needs be.</li>
<li>Param2 = 13. This is the more important of the parameters. If you are getting too many circles then increase this number, and vice versa. Small changes to this make large differences!</li>
<li>minRadius - the smallest radius allowed for a circle.</li>
<li>MaxRadius - the largest radius allowed for a circle.</li>
</ul>
<br />
HoughCircle returns a x and y co-ordinate for each circle. It also returns a radius. We are storing these values in the variable called circles.<br />
<br />
Again there is more information available about HoughCircle on the function detection page of the openCV documentation under HoughCircles.<br />
<br />
<a href="http://docs.opencv.org/modules/imgproc/doc/feature_detection.htm">http://docs.opencv.org/modules/imgproc/doc/feature_detection.htm</a>l<br />
<br />
We now go through each of these circles in order. For each of the circles we draw its circumference and its centre onto the coloured image we stored in the variable img.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">i</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">circles</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,:]:</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#draw the outer circle</span>
<span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">circle</span><span class="p">(</span><span class="n">img</span><span class="p">,(</span><span class="n">i</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">],</span><span class="n">i</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]),</span><span class="n">i</span><span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">],(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">),</span><span class="mi" style="color: #40a070;">2</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#draw the centre of the circle</span>
<span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">circle</span><span class="p">(</span><span class="n">img</span><span class="p">,(</span><span class="n">i</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">],</span><span class="n">i</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]),</span><span class="mi" style="color: #40a070;">2</span><span class="p">,(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">),</span><span class="mi" style="color: #40a070;">3</span><span class="p">)</span></pre>
<br />
More information on the circle command is seen on the OpenCV docs page which covers drawing functions.<br />
<br />
<a href="http://docs.opencv.org/modules/core/doc/drawing_functions.html">http://docs.opencv.org/modules/core/doc/drawing_functions.html</a><br />
<br />
Now as I stated at the start of this blog there was an actual reason for writing this program. I wanted to be able to log the x and y co-ordinates of the circles to see how they varied when putting in different items. I also wanted to work out the angle between the circles, and see how that varied.<br />
<br />
The next lines of code separate out the x and y co-ordinates. They also work out the angle between them using simple trigonometry.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">##Determine co-ordinates for centre of circle</span>
<span class="n">x1</span> <span class="o" style="color: #666666;">=</span> <span class="n">circles</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">][</span><span class="mi" style="color: #40a070;">0</span><span class="p">][</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span>
<span class="n">y1</span> <span class="o" style="color: #666666;">=</span> <span class="n">circles</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">][</span><span class="mi" style="color: #40a070;">0</span><span class="p">][</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span>
<span class="n">x2</span> <span class="o" style="color: #666666;">=</span> <span class="n">circles</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">][</span><span class="mi" style="color: #40a070;">1</span><span class="p">][</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span>
<span class="n">y2</span> <span class="o" style="color: #666666;">=</span> <span class="n">circles</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">][</span><span class="mi" style="color: #40a070;">1</span><span class="p">][</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span>
<span class="c" style="color: #60a0b0; font-style: italic;">##Angle betwen two circles</span>
<span class="n">theta</span> <span class="o" style="color: #666666;">=</span> <span class="n">math</span><span class="o" style="color: #666666;">.</span><span class="n">degrees</span><span class="p">(</span><span class="n">math</span><span class="o" style="color: #666666;">.</span><span class="n">atan</span><span class="p">((</span><span class="n">y2</span><span class="o" style="color: #666666;">-</span><span class="n">y1</span><span class="p">)</span><span class="o" style="color: #666666;">/</span><span class="p">(</span><span class="n">x2</span><span class="o" style="color: #666666;">-</span><span class="n">x1</span><span class="p">)))</span></pre>
<br />
Finally to display the images nicely on the Raspberry Pi I pass each image through the function to resize them...<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">##Resize image</span>
<span class="n">img</span> <span class="o" style="color: #666666;">=</span> <span class="n">resizeImage</span><span class="p">(</span><span class="n">img</span><span class="p">)</span>
<span class="n">thresh</span> <span class="o" style="color: #666666;">=</span> <span class="n">resizeImage</span><span class="p">(</span><span class="n">thresh</span><span class="p">)</span></pre>
<br />
...then I display the images.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">##Show Images </span>
<span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">imshow</span><span class="p">(</span><span class="s" style="color: #4070a0;">"thresh"</span><span class="p">,</span><span class="n">thresh</span><span class="p">)</span>
<span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">imshow</span><span class="p">(</span><span class="s" style="color: #4070a0;">"img"</span><span class="p">,</span><span class="n">img</span><span class="p">)</span>
</pre>
<div>
<span class="p"><br /></span></div>
<div>
<span class="p">There is no need to display the images if you don't want to. However I think its good to see what the thresh image and the final image looks like. These are good to help any fault finding. </span></div>
<div>
<span class="p"><br /></span></div>
You also need the next line for the code to work.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">cv2</span><span class="o" style="color: #666666;">.</span><span class="n">waitKey</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">)</span></pre>
<br />
Here is a link to the code, so you can download it rather than type it.<br />
<br />
<div style="text-align: left;">
<a href="https://drive.google.com/file/d/0B87aGq7vEpoFZ21BTlE5MXpPcTA/edit?usp=sharing" target="_blank">HoughCircles.py</a></div>
<br />
If you don't have a Raspberry Pi Camera there are a few images below which you can use to test your code on. Just change the code to comment out the line about taking the image with the camera, and change the name of the files you are opening to suit.<br />
<br />
The first one is taken using my Raspberry Pi camera.<br />
<br />
<a href="https://drive.google.com/file/d/0B87aGq7vEpoFZ3hDYjlub01rdEk/edit?usp=sharing">Hough_image1.jpg</a><br />
<br />
The second is from my phone.<br />
<br />
<a href="https://drive.google.com/file/d/0B87aGq7vEpoFdDFQNGlxbWZUU1U/edit?usp=sharing">Hough_image2.jpg</a><br />
<br />
If you have any problems with the code, try it on these two images first, as I know these work. I think most problems you will have will be to do with lighting. There was a fair amount of playing around with certain parameters, particularly param2 to get this to work.<br />
<br />
Keep an eye on my blog, as there could well be some more openCV programs at some point!<br />
<br />Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com9tag:blogger.com,1999:blog-8250429656532783188.post-41472140985098339472013-10-07T12:18:00.000+01:002013-10-07T12:39:49.064+01:00Guide to Creating a Sudoku Solver using Python and PygameAfter creating a version of <a href="http://trevorappleton.blogspot.co.uk/2013/07/python-game-of-life.html" target="_blank">Conways Game of Life in Python</a> I was keen to explore Pygame further. The Game of Life program I wrote demonstrated that Pygame was a great way to graphically show information, but it didn't explore any interactive elements of Pygame.<br />
<br />
My default method for anything that requires a GUI (Graphical User Interface) is to use Tkinter. In fact I have written a blog post which explains how to create a basic GUI in Tkinter.<br />
<br />
<a href="http://trevorappleton.blogspot.co.uk/2013/05/python-rock-paper-scissors-inside-gui.html" target="_blank">Python - Rock Paper Scissors inside a GUI</a><br />
<br />
Tkinter does the job of GUI creation well, and if you need buttons and space for users to type information, it's good. However I often feel it is not very dynamic. When you want the screen to update depending on your interaction with it, it is cumbersome.<br />
<br />
I was curious to see if Pygame would fare any better. While thinking of a way to test this out the idea of writing a Sudoku solver popped into my head. For those who are unsure of what a Sudoku is it is a logic based number puzzle. Further details can be found on the <a href="http://en.wikipedia.org/wiki/Sudoku" target="_blank">Sudoku wiki page</a>.<br />
<br />
I thought this would be perfect for interacting with as the user would have to select which numbers are known in the blank Sudoko, and it would have to update depending on the information given.<br />
<br />
Before getting too excited, the Sudoku solver in this blog post will not solve all Sudoku. It will only solve basic Sudoku. The reason for this is I wanted to show the Sudoku updating as more information was supplied to it. Therefore this solver works in the way a human would solve the puzzle, rather than using a brute force method of running through all possibilities. As puzzles get more complex, so do the methods people employ to solve them. I have programmed just a couple of these as they were enough to demonstrate this interaction between the user and the screen. However the program you will end up with can be adapted to include other methods people use to solve Sudoku. If I feel so inclined, I may cover these in a future blog post.<br />
<br />
Pygame comes as standard on the Raspberry Pi, so there is no installation required, however if you are using a different platform for programming then you can download it from here:<br />
<br />
http://www.pygame.org/news.html<br />
<br />
For those of you who have read my blog post about the Game of Life you will have seen that I highly rate the work of Al Sweigart. He has written three excellent books about programming in Python. These are called 'Invent Your Own Computer Games with Python', 'Making Games with Python and Pygame' and 'Hacking Secret Ciphers with Python'. All three are free and can be found on the website <a href="http://inventwithpython.com/">http://inventwithpython.com</a><br />
<br />
Details of how Pygame works is outside of the scope of this blog, and besides Al Sweigart does a better job than I could of explaining it. If you would like further details you will find them in his book 'Making Games with Python and Pygame'.<br />
<br />
I have broken the development of this program down into smaller steps, so you can see how the program evolved as I programmed it.<br />
<br />
There are eight steps.<br />
<br />
1. Draw a blank pygame screen<br />
2. Draw a grid on the screen<br />
3. Populate a completely blank puzzle<br />
4. Add in the ability to select different numbers with the mouse<br />
5. Update the screen as numbers are selected<br />
6. Implement the first method of solving Sudoku<br />
7. Allowing correction of mistakes<br />
8. Implement a second method of solving Sudoku<br />
<br />
As I ask you to type code, I will often show not only the line you need to type in but a few extra lines to illustrate where you should type the code.<br />
<br />
<b>Step 1 - Draw a blank screen</b><br />
<br />
The purpose of this section is to create a blank screen as shown below.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv9joiIBFEVrG3Ux1KQV2s9mQmynmaI5xZszlIK9R5Gxzg5hrirnloxAUv3hug0u7lLZGcFPufDJzxswTrXbRNcyCod5EXCHYFC1SsU9U-B2G-j8aTTmaTIEazjZW0fwDe98o7qiELU1U/s1600/SudokuSolver_Step1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv9joiIBFEVrG3Ux1KQV2s9mQmynmaI5xZszlIK9R5Gxzg5hrirnloxAUv3hug0u7lLZGcFPufDJzxswTrXbRNcyCod5EXCHYFC1SsU9U-B2G-j8aTTmaTIEazjZW0fwDe98o7qiELU1U/s320/SudokuSolver_Step1.PNG" width="293" /></a></div>
<br />
The first thing I needed to achieve was to get a blank screen up and running. As I mentioned in my <a href="http://trevorappleton.blogspot.co.uk/2013/07/python-game-of-life.html" target="_blank">Game of Life blog</a> Al Sweigart provided the code to do this, so I did not have to go re-inventing the wheel.<br />
<br />
Type in the following and then press F5 to save and run the code.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">pygame</span><span class="o" style="color: #666666;">,</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">sys</span>
<span class="kn" style="color: #007020; font-weight: bold;">from</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">pygame.locals</span> <span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">init</span><span class="p">()</span>
<span class="n">DISPLAYSURF</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_mode</span><span class="p">((</span><span class="mi" style="color: #40a070;">400</span><span class="p">,</span><span class="mi" style="color: #40a070;">300</span><span class="p">))</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_caption</span><span class="p">(</span><span class="s" style="color: #4070a0;">'Hello World'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">while</span> <span class="bp" style="color: #007020;">True</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;">#main game loop</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">event</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">QUIT</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">quit</span><span class="p">()</span>
<span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span></pre>
While this works and creates a blank Pygame window I am going to develop this code a little at this stage.<br />
<br />
The first thing I will do is add all the code, other than the import statements, into a main function.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">main</span><span class="p">():</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">init</span><span class="p">()</span>
<span class="n">DISPLAYSURF</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_mode</span><span class="p">((</span><span class="mi" style="color: #40a070;">400</span><span class="p">,</span><span class="mi" style="color: #40a070;">300</span><span class="p">))</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_caption</span><span class="p">(</span><span class="s" style="color: #4070a0;">'Hello World'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">while</span> <span class="bp" style="color: #007020;">True</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;">#main game loop</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">event</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">QUIT</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">quit</span><span class="p">()</span>
<span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span></pre>
Then add some code at the very end of the program to call the main function.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"> <span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span></pre>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">__name__</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span></pre>
We also need to add the global variables FPSCLOCK and DISPLAYSURF into the main function.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">main</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">global</span> <span class="n">FPSCLOCK</span><span class="p">,</span> <span class="n">DISPLAYSURF</span></pre>
and under the pygame.init() command define what these global variables are:<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">init</span><span class="p">()</span>
<span class="n">FPSCLOCK</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">time</span><span class="o" style="color: #666666;">.</span><span class="n">Clock</span><span class="p">()</span>
<span class="n">DISPLAYSURF</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_mode</span><span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span>DISPLAYSURF was already there, but you will see that I have replaced the 400 and 300 with a couple of global variables, WINDOWWIDTH and WINDOWHEIGHT. So lets ensure we specify those global variables in our code, put them outside the main function, under the two import statements.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">pygame</span><span class="o" style="color: #666666;">,</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">sys</span>
<span class="kn" style="color: #007020; font-weight: bold;">from</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">pygame.locals</span> <span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># Sets size of grid</span>
<span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">270</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">270</span></pre>
Why have I done this? Well in future if I want to modify the width or height of the window it would be quite hard to find the location of the 400 and 300 within my program. If I was reading my code it is not obvious what these values relate to. By using global variables such as WINDOWWIDTH and WINDOWHEIGHT the meaning is very obvious. It also means if I need to use the values of width or height again in the program, and then decide to modify those values, I only have to change the values at one central location. It makes my code easier to read and modify, which has to be a good thing!<br />
<br />
The other thing we will want is to keep the screen updated at regular intervals, to ensure it captures any changes. We can dictate the number of Frames Per Second (FPS) which dictates how often our program updates. Each time the program updates is often referred to as a tick. So 10 frames Per Second would mean the program runs through 10 ticks every second.<br />
<br />
First of all lets set a global variable to determine the number of FPS we would like our program to run with.<br />
<br />
Under the two import statements, but above the variables WINDOWWIDTH and WINDOWHEIGHT add the following.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">pygame</span><span class="o" style="color: #666666;">,</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">sys</span>
<span class="kn" style="color: #007020; font-weight: bold;">from</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">pygame.locals</span> <span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Number of frames per second</span>
<span class="n">FPS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">10</span></pre>
We need to tell our program we want it to run a new tick using the value in the FPS global variable. So at the bottom of the while loop add FPSCLOCK.tick(FPS).<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span>
<span class="n">FPSCLOCK</span><span class="o" style="color: #666666;">.</span><span class="n">tick</span><span class="p">(</span><span class="n">FPS</span><span class="p">)</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span>Finally lets make the background white. To do this we use the DISPLAYSURF.fill command. The command expects you to input a colour in terms of the amount of Red, Green and Blue used to make up the colour. These three values are often referred to as RGB. However as with the window width and height it makes sense to define the colours in one place. Then if you need to modify them there is one central location to do so.<br />
<br />
So under the size of the grid variables set a global variable for white.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;"># Sets size of grid</span>
<span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">270</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">270</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># Set up the colours</span>
<span class="n">WHITE</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">)</span></pre>
And within the main loop use DISPLAYSURF.fill to set the background to white.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_caption</span><span class="p">(</span><span class="s" style="color: #4070a0;">'Sudoku Solver'</span><span class="p">)</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">(</span><span class="n">WHITE</span><span class="p">)</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span>Oh and don't forget to change the name of the window from 'Hello World' to 'Sudoku Solver'.<br />
<br />
Press F5 to run the program. Does it look like the image at the start of this section?<br />
<br />
<a href="https://docs.google.com/file/d/0B87aGq7vEpoFVXQzM0RsUnIya2s/edit?usp=sharing" target="_blank">Sudoku Step 1 Source Code</a><br />
<br />
<b>Step 2 - Draw a grid on the screen</b><br />
<b><br /></b>
The purpose of this section is to update our blank screen with grid lines.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC1v4VJkbzwO5WED4Fwsz7R7DePVjxpqveo0XGSnacqav0dAXoBWhMDbl2XzETNSwKSRqAlqnCIB94gnvERcT8KbEAfhY0DyLpBCxGRUbP1-j6wQEJuTJf1treN5uodrvgHQVtfUlmJbg/s1600/SudokuSolver_Step2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC1v4VJkbzwO5WED4Fwsz7R7DePVjxpqveo0XGSnacqav0dAXoBWhMDbl2XzETNSwKSRqAlqnCIB94gnvERcT8KbEAfhY0DyLpBCxGRUbP1-j6wQEJuTJf1treN5uodrvgHQVtfUlmJbg/s320/SudokuSolver_Step2.PNG" width="306" /></a></div>
<b><br /></b>
<br />
We would like to draw a grid on the screen to map out our Sudoku puzzle. When you look at a Sudoku grid you see that it is made up of a grid of 3 x 3 squares. Each of these squares is in turn made up of a 3 x 3 grid. The large squares are usually separated by a darker line than the smaller squares as shown above.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
The first thing we want to do is to create a few more colours. We want a black and a light gray. Again we will create these as global variables.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;"># Set up the colours</span>
<span class="n">BLACK</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="mi" style="color: #40a070;">0</span><span class="p">)</span>
<span class="n">WHITE</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">)</span>
<span class="n">LIGHTGRAY</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">200</span><span class="p">,</span> <span class="mi" style="color: #40a070;">200</span><span class="p">,</span> <span class="mi" style="color: #40a070;">200</span><span class="p">)</span></pre>
We will create a function, lets call it drawGrid(), which holds all the code to draw the grid. We will call the function to draw the grid within our main function. The first time we draw the grid we will draw it outside of the while loop in the main function, but we do want to draw the grid after we have made the background white, otherwise we will be overwriting our grid. Therefore after making the background white call the function drawGrid().<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"> <span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">(</span><span class="n">WHITE</span><span class="p">)</span>
<span class="n">drawGrid</span><span class="p">()</span></pre>
</pre>
Before we get into writing the drawGrid() function we should have a think about what information we need in order to draw the grid.<br />
<br />
We need our window height and width splitting into three equal sizes to create the larger squares. We also need to split the height and width of the window into 9 smaller squares to make the smaller cells. It's in effect a 9 x 9 grid we are looking at.<br />
<br />
We probably don't want the small squares to be too small as we are going to want to display something in there, it would not be much of a Sudoku solver if we could not display numbers!<br />
<br />
When we talk about window height and width, we define these in terms of number of pixels. Therefore to make the division nice it would be good if we could only make the window a size that is divisible by 9 and keep it as whole numbers (integers).<br />
<br />
Therefore if I create a global variable which defines the WINDOWSIZE as 90 and a second called WINDOWMULTIPLIER which would be an integer. We can say that WINDOWSIZE x WINDOWMULTIPLIER will always be divisible by 9, and the smallest value of WINDOWSIZE x WINDOWMULTIPLIER when divided by 9 will be 10. We all know 90 / 9 = 10.<br />
<br />
So under the FPS global variable type the following<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">FPS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">10</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># Sets size of grid</span>
<span class="n">WINDOWMULTIPLIER</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span>
<span class="n">WINDOWSIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">90</span></pre>
We can use this value to then set the size of the window by making<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWSIZE</span> <span class="o" style="color: #666666;">*</span> <span class="n">WINDOWMULTIPLIER</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWSIZE</span> <span class="o" style="color: #666666;">*</span> <span class="n">WINDOWMULTIPLIER</span></pre>
These should replace the existing values for WINDOWHEIGHT and WINDOWWIDTH.<br />
So if we wanted to make the window larger or smaller we only need to change the value in WINDOWMULTIPLIER and we know this will always be divisible by 9 and will mean the smaller squares don't get too small.<br />
<br />
Now to get the size of the 3 x 3 group of cells divided by the darker lines, lets call these squares, we can divide the size of the window by three. Rather than doing this each time it would be easier if we could just call a global variable with the right information in there.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;">SQUARESIZE <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWSIZE</span> <span class="o" style="color: #666666;">*</span> <span class="n">WINDOWMULTIPLIER</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span> <span class="mi" style="color: #40a070;">3</span></pre>
and if we divide SQUARESIZE by 3 we will get the size of the smaller cells.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;">CELLSIZE <span class="o" style="color: #666666;">=</span> SQUARE<span class="n">SIZE</span> <span class="o" style="color: #666666;">/</span> <span class="mi" style="color: #40a070;">3</span></pre>
OK so we should now have the following global variables typed under the FPS global variable.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;"># Sets size of grid</span>
<span class="n">WINDOWMULTIPLIER</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span> <span class="c" style="color: #60a0b0; font-style: italic;"># Modify this number to change size of grid</span>
<span class="n">WINDOWSIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">90</span>
<span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWSIZE</span> <span class="o" style="color: #666666;">*</span> <span class="n">WINDOWMULTIPLIER</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWSIZE</span> <span class="o" style="color: #666666;">*</span> <span class="n">WINDOWMULTIPLIER</span>
<span class="n">SQUARESIZE</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">WINDOWSIZE</span> <span class="o" style="color: #666666;">*</span> <span class="n">WINDOWMULTIPLIER</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span> <span class="mi" style="color: #40a070;">3</span>
<span class="n">CELLSIZE</span> <span class="o" style="color: #666666;">=</span> SQUARE<span class="n">SIZE</span> <span class="o" style="color: #666666;">/</span> <span class="mi" style="color: #40a070;">3</span></pre>
I have added a note to the WINDOWMULTIPLIER to remind me in the future to modify that value if I want to change the size of the window.<br />
<br />
Armed with all this information about the size of the grid we are now able to write our function to draw the grid.<br />
<br />
Under the global variables you should create a new function called drawGrid.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">LIGHTGRAY</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">200</span><span class="p">,</span> <span class="mi" style="color: #40a070;">200</span><span class="p">,</span> <span class="mi" style="color: #40a070;">200</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">drawGrid</span><span class="p">():</span></pre>
First lets look at the code for the whole function and then look into the individual lines.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">drawGrid</span><span class="p">():</span>
<span class="c" style="color: #60a0b0; font-style: italic;">### Draw Minor Lines</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="n">WINDOWWIDTH</span><span class="p">,</span> <span class="n">CELLSIZE</span><span class="p">):</span> <span class="c" style="color: #60a0b0; font-style: italic;"># draw vertical lines</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">LIGHTGRAY</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">),(</span><span class="n">x</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">y</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="n">WINDOWHEIGHT</span><span class="p">,</span> <span class="n">CELLSIZE</span><span class="p">):</span> <span class="c" style="color: #60a0b0; font-style: italic;"># draw horizontal lines</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">LIGHTGRAY</span><span class="p">,</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="n">y</span><span class="p">),</span> <span class="p">(</span><span class="n">WINDOWWIDTH</span><span class="p">,</span> <span class="n">y</span><span class="p">))</span>
<span class="c" style="color: #60a0b0; font-style: italic;">### Draw Major Lines</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="n">WINDOWWIDTH</span><span class="p">,</span> <span class="n">SQUARESIZE</span><span class="p">):</span> <span class="c" style="color: #60a0b0; font-style: italic;"># draw vertical lines</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">BLACK</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">),(</span><span class="n">x</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">y</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="n">WINDOWHEIGHT</span><span class="p">,</span> <span class="n">SQUARESIZE</span><span class="p">):</span> <span class="c" style="color: #60a0b0; font-style: italic;"># draw horizontal lines</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">BLACK</span><span class="p">,</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="n">y</span><span class="p">),</span> <span class="p">(</span><span class="n">WINDOWWIDTH</span><span class="p">,</span> <span class="n">y</span><span class="p">))</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
</pre>
We are drawing the grid lines to separate the smaller cells first. If we draw the darker lines which separate the larger cells first, the lighter ones would over write these.<br />
<br />
First we will draw the vertical lines<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="n">WINDOWWIDTH</span><span class="p">,</span> <span class="n">CELLSIZE</span><span class="p">):</span> <span class="c" style="color: #60a0b0; font-style: italic;"># draw vertical lines</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">LIGHTGRAY</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">),(</span><span class="n">x</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span></pre>
</pre>
The first line in this code is saying make x = 0. Then add the value CELLSIZE to x. Repeat until x reaches the value in WINDOWWIDTH.<br />
<br />
The second line indicates what to do at each of these increments. It says draw a line on DISPLAYSURF, using the colour LIGHTGRAY, starting at co-ordinate (x,0) and ending at (x, WINDOWHEIGHT)<br />
<br />
So the line starts at y = 0 and ends at y = WINDOWHEIGHT meaning the line is vertical the full length of the screen. x varies at each increment, meaning vertical lines are draw along the screen at intervals dictated by CELLSIZE.<br />
<br />
Try running the code at this stage to see if it gives you what you expected. Did you see this?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqAFgLQ-Kb4GNBwnSIeFGEEp1BeLM1Ez3bCDabo7mL83PY2b-oZKA9kBdDhrhuJq5lnsnuTfFv-Z8NY0kuz-XGL-ajqjZOC-lpc6SG65WmbV1sHoZ59S-McLJLtqDV5F9AkQRrt98KDhE/s1600/SudokuVerticalLines.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqAFgLQ-Kb4GNBwnSIeFGEEp1BeLM1Ez3bCDabo7mL83PY2b-oZKA9kBdDhrhuJq5lnsnuTfFv-Z8NY0kuz-XGL-ajqjZOC-lpc6SG65WmbV1sHoZ59S-McLJLtqDV5F9AkQRrt98KDhE/s320/SudokuVerticalLines.png" width="307" /></a></div>
Great!<br />
<br />
This code can easily be modified to draw the horizontal lines.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">y</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="n">WINDOWHEIGHT</span><span class="p">,</span> <span class="n">CELLSIZE</span><span class="p">):</span> <span class="c" style="color: #60a0b0; font-style: italic;"># draw horizontal lines</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">LIGHTGRAY</span><span class="p">,</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="n">y</span><span class="p">),</span> <span class="p">(</span><span class="n">WINDOWWIDTH</span><span class="p">,</span> <span class="n">y</span><span class="p">))</span></pre>
</pre>
Notice that it is y that is changing each time, and not x. All horizontal lines runs from 0 to WINDOWWIDTH.<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
The very same principle is used for the horizontal and vertical lines for the thicker lines.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;">### Draw Major Lines</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="n">WINDOWWIDTH</span><span class="p">,</span> <span class="n">SQUARESIZE</span><span class="p">):</span> <span class="c" style="color: #60a0b0; font-style: italic;"># draw vertical lines</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">BLACK</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">),(</span><span class="n">x</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">y</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="n">WINDOWHEIGHT</span><span class="p">,</span> <span class="n">SQUARESIZE</span><span class="p">):</span> <span class="c" style="color: #60a0b0; font-style: italic;"># draw horizontal lines</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">BLACK</span><span class="p">,</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="n">y</span><span class="p">),</span> <span class="p">(</span><span class="n">WINDOWWIDTH</span><span class="p">,</span> <span class="n">y</span><span class="p">))</span></pre>
</pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span>However the colour used is BLACK and the separation is SQUARESIZE and not CELLSIZE<br />
<br />
Finally finish the function with<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
Try running the program. Do you see the image at the top of this section?<br />
<br />
Great that finishes of the second part of the program!<br />
<br />
<a href="https://docs.google.com/file/d/0B87aGq7vEpoFN1diTzhYV0IwbTA/edit?usp=sharing" target="_blank">Sudoku Step 2 Source Code</a><br />
<br />
<b>Step 3 - Populate a completely blank puzzle</b><br />
<b><br /></b>
The purpose of this section is to show the remaining numbers available for each cell in the grid. This will allow us to pick the number we want to populate that cell, and to display the remaining numbers as we start to solve our Sudoku.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsVrXkpgyUEE1Pef5rCyoN05b14UFHXRkBwVJjTuvONKDNYUL_VB0toOjI1sEx9_SrMa88HDpb0QXLDndzooYVYl_7M4_PNJ4Lhk9oXcpP3XwKHY9v9RWUVyQ2uDSHL2n2zPXrguoi9pc/s1600/SudokuSolver_Step3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsVrXkpgyUEE1Pef5rCyoN05b14UFHXRkBwVJjTuvONKDNYUL_VB0toOjI1sEx9_SrMa88HDpb0QXLDndzooYVYl_7M4_PNJ4Lhk9oXcpP3XwKHY9v9RWUVyQ2uDSHL2n2zPXrguoi9pc/s320/SudokuSolver_Step3.PNG" width="306" /></a></div>
<b><br /></b>Now we have our blank grid looking good we can start the serious work of populating it. The first thing we need to consider is how are we going to input the number into each square, and how are we going to feedback the potential remaining numbers as our Sudoko starts to be solved?<br />
<br />
We could put all 9 possible numbers (1-9) in each of the smaller grids. We could then highlight the number we wanted to choose with a mouse click. If all 9 potential numbers are shown initially in a grid, once we can rule out any potential numbers from a square we could remove them leaving only the numbers which are still available to be picked.<br />
<br />
This sounds like a good plan to me.<br />
<br />
Therefore the aim of this stage is to get the numbers 1-9 all nicely placed in each small grid. There are 81 grids so we need to do this for each of the grids.<br />
<br />
To place the numbers 1-9 in one of the small grids, it would be best to split them into 3 rows of 3 as so:<br />
<br />
123<br />
456<br />
789<br />
<br />
To position each of these numbers it sounds as though we need to split each cell so it is made up of 9 smaller squares. First of all add an extra global variable which will help us with that. As this is to determine the space for the numbers lets call this NUMBERSIZE. Therefore below the line<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">CELLSIZE</span> <span class="o" style="color: #666666;">=</span> SQUARE<span class="n">SIZE</span> <span class="o" style="color: #666666;">/</span> <span class="mi" style="color: #40a070;">3</span> <span class="c" style="color: #60a0b0; font-style: italic;"># Size of a cell</span></pre>
Add the following line:<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">NUMBERSIZE</span> <span class="o" style="color: #666666;">=</span> <span class="n">CELLSIZE</span> <span class="o" style="color: #666666;">/</span><span class="mi" style="color: #40a070;">3</span> <span class="c" style="color: #60a0b0; font-style: italic;"># Position of unsolved number</span></pre>
The size for each number is 1/3 of each CELLSIZE.<br />
<br />
As we are now in effect dividing the window size by three, then three again (total of 9) and three again (total of 27) and all our global variables are integers (whole numbers) we need ideally want our window size to be a multiple of 3, 9 and 27. Therefore make the window size = 81. This avoids a bug later which I found to be caused by rounding errors!<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">WINDOWSIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">81</span></pre>
Before we get carried away with how we are going to display all the numbers, we need a method of storing the remaining numbers for each of the 81 cells. We know there are 9 cells across and 9 cells down, so we can uniquely identify each one by a simple co-ordinate system i.e. (0,0),(0,1),(0,2)......(8,7),(8,8)<br />
<br />
The best way is to use a Python Dictionary. Dictionaries have keys and values. By knowing the key you can find the associated value.<br />
<br />
If we use the co-ordinates as a key in a dictionary, we can have a list of the potential numbers as the value associated with that key. So for instance the first cell will have the Key (0,0) and the Value [1,2,3,4,5,6,7,8,9] as we have no solved parts of the Sudoku yet. In fact all the Values in the dictionary will be [1,2,3,4,56,7,8,9] to start.<br />
<br />
As we only need to create the dictionary once, lets create a function to do this called initiateCells()<br />
<br />
Here is the full function first of all then we will break it down line by line.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">initiateCells</span><span class="p">():</span>
<span class="n">currentGrid</span> <span class="o" style="color: #666666;">=</span> <span class="p">{}</span>
<span class="n">fullCell</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">7</span><span class="p">,</span><span class="mi" style="color: #40a070;">8</span><span class="p">,</span><span class="mi" style="color: #40a070;">9</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">xCoord</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">9</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">yCoord</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">9</span><span class="p">):</span>
<span class="n">currentGrid</span><span class="p">[</span><span class="n">xCoord</span><span class="p">,</span><span class="n">yCoord</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">list</span><span class="p">(</span><span class="n">fullCell</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;"># Copies List</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGrid</span></pre>
Place this function below the drawGrid function.<br />
<br />
The first line is creating the name of the function.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">initiateCells</span><span class="p">():</span></pre>
The second line creates a blank dictionary called currentGrid.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">currentGrid</span> <span class="o" style="color: #666666;">=</span> <span class="p">{}</span></pre>
The third line creates a list called fullCell populated with [1,2,3,4,5,6,7,8,9]<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">fullCell</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">7</span><span class="p">,</span><span class="mi" style="color: #40a070;">8</span><span class="p">,</span><span class="mi" style="color: #40a070;">9</span><span class="p">]</span></pre>
The fourth line runs through the x co-ordinates from 0 up to, but not including 9 i.e. the numbers 0,1,2,3,4,5,6,7,8<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">xCoord</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">9</span><span class="p">):</span></pre>
For each of the numbers from xCoord the fifth line runs through 9 numbers for yCoords, again from 0 up to, but not including 9.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">yCoord</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">9</span><span class="p">):</span></pre>
The above two lines have been quite clever in generating 81 co-ordinates from (0,0) up to (8,8) So for each of these 81 co-ordinates we now create a new item in the dictionary using the co-ordinate as the key and the list in the fullCell as the associated value. list(fullCell) ensures the list is copied, so each co-ordinate has its own list.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">currentGrid</span><span class="p">[</span><span class="n">xCoord</span><span class="p">,</span><span class="n">yCoord</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">list</span><span class="p">(</span><span class="n">fullCell</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;"># Copies List</span></pre>
Finally we return the fully populated dictionary called currentGrid.<br />
<br />
We should call the initiateCells function from our main function so we can use the information we have just created.<br />
<br />
Add the following line as shown below.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">(</span><span class="n">WHITE</span><span class="p">)</span>
<span class="n">currentGrid</span> <span class="o" style="color: #666666;">=</span> <span class="n">initiateCells</span><span class="p">()</span></pre>
This creates a Dictionary in our main function called currentGrid and populates it with what has been returned from the initiateCells function.<br />
<br />
Now we have all the data for each of the cells we need to somehow display that on our grid.<br />
<br />
To do this we will write a function which takes the information in currentGrid. We will call the function displayCells. This should be added beneath the initiateCells function.<br />
<br />
Here is the function and I will then break it down line by line.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;"># Takes the remaining numbers and displays them in the cells.</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">displayCells</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">):</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># Create offset factors to display numbers in right location in cells.</span>
<span class="n">xFactor</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="n">yFactor</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentGrid</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;"># item is x,y co-ordinate from 0 - 8</span>
<span class="n">cellData</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGrid</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="c" style="color: #60a0b0; font-style: italic;"># isolates the numbers still available for that cell</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">number</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">cellData</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;">#iterates through each number</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">number</span> <span class="o" style="color: #666666;">!=</span> <span class="s" style="color: #4070a0;">' '</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;"># ignores those already dismissed</span>
<span class="n">xFactor</span> <span class="o" style="color: #666666;">=</span> <span class="p">((</span><span class="n">number</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span><span class="o" style="color: #666666;">%</span><span class="mi" style="color: #40a070;">3</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;"># 1/4/7 = 0 2/5/8 = 1 3/6/9 =2</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">number</span> <span class="o" style="color: #666666;"><=</span> <span class="mi" style="color: #40a070;">3</span><span class="p">:</span>
<span class="n">yFactor</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">number</span> <span class="o" style="color: #666666;"><=</span><span class="mi" style="color: #40a070;">6</span><span class="p">:</span>
<span class="n">yFactor</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">yFactor</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#(item[0] * CELLSIZE) Positions in the right Cell</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#(xFactor*NUMBERSIZE) Offsets to position number </span>
<span class="n">populateCells</span><span class="p">(</span><span class="n">number</span><span class="p">,(</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">*</span><span class="n">CELLSIZE</span><span class="p">)</span><span class="o" style="color: #666666;">+</span><span class="p">(</span><span class="n">xFactor</span><span class="o" style="color: #666666;">*</span><span class="n">NUMBERSIZE</span><span class="p">),(</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">*</span><span class="n">CELLSIZE</span><span class="p">)</span><span class="o" style="color: #666666;">+</span><span class="p">(</span><span class="n">yFactor</span><span class="o" style="color: #666666;">*</span><span class="n">NUMBERSIZE</span><span class="p">))</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
The first line<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">displayCells</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">):</span></pre>
Tells us that we are creating a function called displayCells. However more importantly it is also saying we are taking the data in currentGrid and passing this into the function for us to use.<br />
<br />
We know that for each of our numbers from 1-9 that we want to display in the grid, we want them in a different location. Otherwise they would all be on top of each other, and unreadable. The next two lines create an offset factor, which is really a co-ordinate, so we can offset the numbers from each other. We will need one for x and one for y.<br />
<span style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;"> </span><span class="c" style="color: #60a0b0; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; font-style: italic;"># Create offset factors to display numbers in right location in cells.</span><br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">xFactor</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="n">yFactor</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span></pre>
The line<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentGrid</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;"># item is x,y co-ordinate from 0 - 8</span></pre>
goes through each of the items we have in currentGrid one at a time.<br />
This is iterating through the Keys in the dictionary, which in this case are the co-ordinates. We want to know what numbers from 1-9 are still available for those co-ordinates, so the next line draws out that information and stores it in a variable called cellData.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">cellData</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGrid</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="c" style="color: #60a0b0; font-style: italic;"># isolates the numbers still available for that cell</span></pre>
Lets look at the next few lines together.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">number</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">cellData</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;">#iterates through each number</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">number</span> <span class="o" style="color: #666666;">!=</span> <span class="s" style="color: #4070a0;">' '</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;"># ignores those already dismissed</span>
<span class="n">xFactor</span> <span class="o" style="color: #666666;">=</span> <span class="p">((</span><span class="n">number</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span><span class="o" style="color: #666666;">%</span><span class="mi" style="color: #40a070;">3</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;"># 1/4/7 = 0 2/5/8 = 1 3/6/9 =2</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">number</span> <span class="o" style="color: #666666;"><=</span> <span class="mi" style="color: #40a070;">3</span><span class="p">:</span>
<span class="n">yFactor</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">number</span> <span class="o" style="color: #666666;"><=</span><span class="mi" style="color: #40a070;">6</span><span class="p">:</span>
<span class="n">yFactor</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">yFactor</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span></pre>
The first of these lines iterates through each number from 1-9 that we have stored in the cellData.<br />
The second line is planning for the future. It says that as we go through the numbers 1-9, if the current number we are up to is NOT a space (remember != means not equal to), which is signified by a ' ', we should carry on with the next few few lines of code.<br />
<br />
Why would any of the numbers be a space and not a number?<br />
<br />
Well as we solve our Sudoku, we are going to have to keep track of which numbers are no longer available to us. If a number is no longer available for that cell, we will replace it with a space. So this line is telling us to ignore the spaces.<br />
<br />
For each of our numbers we want to be able to put it in the right place in the grid. We decided earlier we would like them to be shown as<br />
<br />
1 2 3<br />
4 5 6<br />
7 8 9<br />
<br />
If we treat each of these positions as co-ordinates we see that:<br />
numbers 1,4 & 7 have x co-ordinate 0<br />
numbers 2,5 & 8 have x co-ordinate 1<br />
numbers 3,6 & 9 have x co-ordinate 2<br />
<br />
It is these co-ordinates that we will store in our xFactor and yFactor variables.<br />
<br />
The line<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">xFactor</span> <span class="o" style="color: #666666;">=</span> <span class="p">((</span><span class="n">number</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span><span class="o" style="color: #666666;">%</span><span class="mi" style="color: #40a070;">3</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;"># 1/4/7 = 0 2/5/8 = 1 3/6/9 =2</span>
</pre>
<div>
does exactly that and stores the number 0,1 or 2 in the variable xFactor.</div>
<br />
So how does this work?<br />
<br />
Well the modulus returns the remainder of one number divided by another.<br />
<br />
An example is 10 divided by 3 is 3.3333 or we could say 10 divided by 3 is 3 three whole times, with 1 remainder. therefore 10%3 = 1 as it is returning the remainder.<br />
<br />
Lets calculate the value of a number%3 for numbers from 0-10. You can try this in a python interactive shell if you want to test it out.<br />
<br />
0%3 = 0<br />
1%3 = 1<br />
2%3 = 2<br />
3%3 = 0<br />
4%3 = 1<br />
5%3 = 2<br />
6%3 = 0<br />
7%3 = 1<br />
8%3 = 2<br />
9%3 = 0<br />
10%3 = 1<br />
<br />
We need number 1, 4 and 7 to equal 0. This shows numbers 0, 3 and 6 = 0. So if we minus a 1 off our number before dong the modulus against a 3 this will give us the right value for XOffset. This is why we have (number-1)%3<br />
<br />
The lines for yFactor are much easier to understand, as the code is almost self explanatory.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">number</span> <span class="o" style="color: #666666;"><=</span> <span class="mi" style="color: #40a070;">3</span><span class="p">:</span>
<span class="n">yFactor</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">number</span> <span class="o" style="color: #666666;"><=</span><span class="mi" style="color: #40a070;">6</span><span class="p">:</span>
<span class="n">yFactor</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">yFactor</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">2</span></pre>
If the number is 3 or less, then y factor is 0.<br />
Else if it 6 or less then it is a 1.<br />
Else it is a 2.<br />
<br />
We are now at the stage in the function where for each number we have its position within the cell. What we have to do is combine this information with the information about which cell we are working in so we can plot each number in the right place.<br />
<br />
We will create a separate function, called populateCells in a minute to print the information in the right place. The data we want to pass into this function is the number we want to print and the x and y co-ordinates on the screen where we want to print it.<br />
<br />
Well we know the number is stored in the variable 'number', so that is easy to pass into the function.<br />
The x co-ordinate is made up of two parts. First we need to know the position of the cell we are working in, and secondly where in that cell our number should fit.<br />
<br />
Our program is currently in a couple of for loops. The outer one is<br />
<br />
For item in currentGrid<br />
<br />
Where item becomes the co-ordinates of each cell as we iterate through them. Therefore the x co-ordinate multiplied by the size of the cell, which we have stored in a global variable CELLSIZE, should locate our cell.<br />
<br />
(item[0] * CELLSIZE)<br />
<br />
Now we need to add onto this the location we are in the cell. Well we have just determined the xFactor so if we multiply that by the global variable NUMBERSIZE, that should give the additional offset data within the cell.<br />
<br />
(xFactor*NUMBERSIZE)<br />
<br />
These two added together should give the x co-ordinate of the number.<br />
<br />
(item[0]*CELLSIZE)+(xFactor*NUMBERSIZE)<br />
<br />
Similar deductions show that the y co-ordinate can be determined from.<br />
<br />
(item[1]*CELLSIZE)+(yFactor*NUMBERSIZE)<br />
<br />
So that is how we arrive at the line<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;">#(item[0] * CELLSIZE) Positions in the right Cell</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#(xFactor*NUMBERSIZE) Offsets to position number </span>
<span class="n">populateCells</span><span class="p">(</span><span class="n">number</span><span class="p">,(</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">*</span><span class="n">CELLSIZE</span><span class="p">)</span><span class="o" style="color: #666666;">+</span><span class="p">(</span><span class="n">xFactor</span><span class="o" style="color: #666666;">*</span><span class="n">NUMBERSIZE</span><span class="p">),(</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">*</span><span class="n">CELLSIZE</span><span class="p">)</span><span class="o" style="color: #666666;">+</span><span class="p">(</span><span class="n">yFactor</span><span class="o" style="color: #666666;">*</span><span class="n">NUMBERSIZE</span><span class="p">))</span></pre>
The two lines with a # are just to act as a reminder of what the different aspects refer to, which will help if we are reading our code in the future.<br />
<br />
Finally we type<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
Now we have passed the number, and co-ordinates into the function populateCells, we need to write that function to print the data in the right location. However before we do that we need to specify a font in the main section of the program.<br />
<br />
Under the pygame.display.set_caption line add in the following three lines<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_caption</span><span class="p">(</span><span class="s" style="color: #4070a0;">'Sudoku Solver'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">global</span> <span class="n">BASICFONT</span><span class="p">,</span> <span class="n">BASICFONTSIZE</span>
<span class="n">BASICFONTSIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">15</span>
<span class="n">BASICFONT</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">font</span><span class="o" style="color: #666666;">.</span><span class="n">Font</span><span class="p">(</span><span class="s" style="color: #4070a0;">'freesansbold.ttf'</span><span class="p">,</span> <span class="n">BASICFONTSIZE</span><span class="p">)</span></pre>
These three lines set the size and type of font, they also make the data global variables for us to use elsewhere.<br />
<br />
Right onto the populateCells function! The completed function is as follows.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;"># writes cellData at given x, y co-ordinates </span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">populateCells</span><span class="p">(</span><span class="n">cellData</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
<span class="n">cellSurf</span> <span class="o" style="color: #666666;">=</span> <span class="n">BASICFONT</span><span class="o" style="color: #666666;">.</span><span class="n">render</span><span class="p">(</span><span class="s" style="color: #4070a0;">'</span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">'</span> <span class="o" style="color: #666666;">%</span><span class="p">(</span><span class="n">cellData</span><span class="p">),</span> <span class="bp" style="color: #007020;">True</span><span class="p">,</span> <span class="n">LIGHTGRAY</span><span class="p">)</span>
<span class="n">cellRect</span> <span class="o" style="color: #666666;">=</span> <span class="n">cellSurf</span><span class="o" style="color: #666666;">.</span><span class="n">get_rect</span><span class="p">()</span>
<span class="n">cellRect</span><span class="o" style="color: #666666;">.</span><span class="n">topleft</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">blit</span><span class="p">(</span><span class="n">cellSurf</span><span class="p">,</span> <span class="n">cellRect</span><span class="p">)</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span>I will not go into much detail on this function as they are pygame commands to allow us to print. The important thing is we are printing the number we have passed into it at the co-ordinates given, using the colour LIGHTGRAY, and the font BASICFONT.<br />
<br />
The final thing we want to do is to call the displayCells function from our main function and populate it with the information we generated earlier from our initiateCells function. This will make sure our program makes use of the functions we have just written. Therefore add the following line into the main function below the currentGrid = initiateCells() line.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">currentGrid</span> <span class="o" style="color: #666666;">=</span> <span class="n">initiateCells</span><span class="p">()</span>
<span class="n">displayCells</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">)</span></pre>
<span class="Apple-tab-span" style="white-space: pre;"> </span>Press F5 to run and test the program. Do you see the picture shown at the top of this section?<br />
<br />
<a href="https://docs.google.com/file/d/0B87aGq7vEpoFb0tSZVU4TzNyUzQ/edit?usp=sharing" target="_blank">Sudoku Step 3 Source Code</a><br />
<br />
<b>Step 4 - Add in the ability to select different numbers with the mouse</b><br />
<b><br /></b>
The purpose of this section is to highlight the number the mouse is hovering over, and to report back the location to the user.<br />
<b><br /></b>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKPHqd5BRR5qfhljgivN6RdcjlYYxe4X1lR7QK14CkjbPI8sCE1DQzceeDUMiS5j_VQAJ2uadtUzKZ7ELWS90CZB4gHnafZjI6oN8eeLii3kQy-yg4FBG5ygq1JPst3Beqikh6jFrkYro/s1600/SudokuSolver_Step4.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKPHqd5BRR5qfhljgivN6RdcjlYYxe4X1lR7QK14CkjbPI8sCE1DQzceeDUMiS5j_VQAJ2uadtUzKZ7ELWS90CZB4gHnafZjI6oN8eeLii3kQy-yg4FBG5ygq1JPst3Beqikh6jFrkYro/s320/SudokuSolver_Step4.PNG" width="308" /></a></div>
<b><br /></b>
The first thing we want to do is to create a few variables to store the co-ordinates of the mouse pointer, and to store if the mouse has been clicked or not. These variables should be put into the main function as shown.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"> <span class="n">DISPLAYSURF</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_mode</span><span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span>
<span class="n">mouseClicked</span> <span class="o" style="color: #666666;">=</span> <span class="bp" style="color: #007020;">False</span>
<span class="n">mousex</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="n">mousey</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span></pre>
</pre>
Now we are going to modify the While loop in the main function so it will recognise mouse events.<br />
<br />
At the moment the loop is as follows:<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">while</span> <span class="bp" style="color: #007020;">True</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;">#main game loop</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">event</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">QUIT</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">quit</span><span class="p">()</span>
<span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span>
<span class="n">FPSCLOCK</span><span class="o" style="color: #666666;">.</span><span class="n">tick</span><span class="p">(</span><span class="n">FPS</span><span class="p">)</span></pre>
This loop should become:<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">while</span> <span class="bp" style="color: #007020;">True</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;">#main game loop</span>
<span class="n">mouseClicked</span> <span class="o" style="color: #666666;">=</span> <span class="bp" style="color: #007020;">False</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">event</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">QUIT</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">quit</span><span class="p">()</span>
<span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># mouse movement commands</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">MOUSEMOTION</span><span class="p">:</span>
<span class="n">mousex</span><span class="p">,</span> <span class="n">mousey</span> <span class="o" style="color: #666666;">=</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">pos</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Mouse click commands</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">MOUSEBUTTONUP</span><span class="p">:</span>
<span class="n">mousex</span><span class="p">,</span> <span class="n">mousey</span> <span class="o" style="color: #666666;">=</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">pos</span>
<span class="n">mouseClicked</span> <span class="o" style="color: #666666;">=</span> <span class="bp" style="color: #007020;">True</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">mouseClicked</span> <span class="o" style="color: #666666;">==</span> <span class="bp" style="color: #007020;">True</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">mousex</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">mousey</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># repaints screen</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">(</span><span class="n">WHITE</span><span class="p">)</span>
<span class="n">displayCells</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">)</span>
<span class="n">drawGrid</span><span class="p">()</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># call function to draw box</span>
<span class="n">drawBox</span><span class="p">(</span><span class="n">mousex</span><span class="p">,</span><span class="n">mousey</span><span class="p">)</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span>
<span class="n">FPSCLOCK</span><span class="o" style="color: #666666;">.</span><span class="n">tick</span><span class="p">(</span><span class="n">FPS</span><span class="p">)</span></pre>
So what has changed and why?<br />
<br />
First of all we have added mouseClicked = False to the start of the main loop. This makes sure that we know what the mouseClicked variable is set to at the start of the function as it is always reset.<br />
<br />
The next few lines don't change as they are about exiting the program correctly.<br />
<br />
After the if command we have the following lines<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;"># mouse movement commands</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">MOUSEMOTION</span><span class="p">:</span>
<span class="n">mousex</span><span class="p">,</span> <span class="n">mousey</span> <span class="o" style="color: #666666;">=</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">pos</span></pre>
This is simply saying that if we have not quit, then check to see if the mouse moves. If it does store the co-ordinates in the variables mousex and mousey which we created and set to 0 earlier.<br />
<br />
We then add another elif command.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;">#Mouse click commands</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">MOUSEBUTTONUP</span><span class="p">:</span>
<span class="n">mousex</span><span class="p">,</span> <span class="n">mousey</span> <span class="o" style="color: #666666;">=</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">pos</span>
<span class="n">mouseClicked</span> <span class="o" style="color: #666666;">=</span> <span class="bp" style="color: #007020;">True</span></pre>
This says if we have not quit or moved the mouse, check if we have clicked the mouse. Again store the position of where this happened in mousex and mousey, but also change mouseClicked to True.<br />
<br />
A quick note on MOUSEBUTTONUP, you can use MOUSEBUTTONDOWN. Its probably quite obvious, but MOUSEBUTTONUP is where you release the mouse button and MOUSEBUTTONDOWN is where you press the button down.<br />
<br />
Both will work equally well.<br />
<br />
We then leave the event for loop and check to see if the mouse was clicked. If it was we print both the x and y co-ordinates.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">mouseClicked</span> <span class="o" style="color: #666666;">==</span> <span class="bp" style="color: #007020;">True</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">mousex</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">mousey</span></pre>
Now we will repaint the screen. By repainting it white, printing the text and the drawing the grid as follows.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;"># repaints screen</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">(</span><span class="n">WHITE</span><span class="p">)</span>
<span class="n">displayCells</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">)</span>
<span class="n">drawGrid</span><span class="p">()</span></pre>
<div>
Actually we use these commands a little higher up, but they are not as neat as here, so lets tidy them up while we are at it.</div>
<br />
Under where we have created BASICFONT re-arrange<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">(</span><span class="n">WHITE</span><span class="p">)</span>
<span class="n">currentGrid</span> <span class="o" style="color: #666666;">=</span> <span class="n">initiateCells</span><span class="p">()</span>
<span class="n">displayCells</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">)</span>
<span class="n">drawGrid</span><span class="p">()</span></pre>
To<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">currentGrid</span> <span class="o" style="color: #666666;">=</span> <span class="n">initiateCells</span><span class="p">()</span> <span class="c" style="color: #60a0b0; font-style: italic;">#sets all cells to have number 1-9</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># repaints screen</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">(</span><span class="n">WHITE</span><span class="p">)</span>
<span class="n">displayCells</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">)</span>
<span class="n">drawGrid</span><span class="p">()</span></pre>
It just keeps our code consistent and a little neater looking. I have also added in a comment explaining the first of those lines.<br />
<br />
The final change we have made is to call a function drawBox, which is to draw a box around the number the mouse is highlighting.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;"># call function to draw box</span>
<span class="n">drawBox</span><span class="p">(</span><span class="n">mousex</span><span class="p">,</span><span class="n">mousey</span><span class="p">)</span>
</pre>
<div>
After adding this line add the following function below the populateCells function.</div>
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">drawBox</span><span class="p">(</span><span class="n">mousex</span><span class="p">,</span> <span class="n">mousey</span><span class="p">):</span>
<span class="n">boxx</span> <span class="o" style="color: #666666;">=</span><span class="p">((</span><span class="n">mousex</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #40a070;">27</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span> <span class="n">WINDOWWIDTH</span><span class="p">)</span> <span class="o" style="color: #666666;">*</span> <span class="p">(</span><span class="n">NUMBERSIZE</span> <span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;"># 27 number of squares</span>
<span class="n">boxy</span> <span class="o" style="color: #666666;">=</span><span class="p">((</span><span class="n">mousey</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #40a070;">27</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span> <span class="n">WINDOWHEIGHT</span><span class="p">)</span> <span class="o" style="color: #666666;">*</span> <span class="p">(</span><span class="n">NUMBERSIZE</span> <span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;"># 27 number of squares</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">BLUE</span><span class="p">,</span> <span class="p">(</span><span class="n">boxx</span><span class="p">,</span><span class="n">boxy</span><span class="p">,</span><span class="n">NUMBERSIZE</span><span class="p">,</span><span class="n">NUMBERSIZE</span><span class="p">),</span> <span class="mi" style="color: #40a070;">1</span><span class="p">)</span></pre>
So what does this function do? Well as you can see it takes the values of mousex and mousey, which hold the co-ordinates of the mouse position.<br />
<br />
The first two lines in this function are similar, one for x and one for y. They take the co-ordinates of where the mouse is and converts them to the start of the box for the number which you are hovering over.<br />
The final line in this function draws a rectangle around the number the mouse is hovering over. This is a pygame command for drawing a rectangle.<br />
<br />
DISPLAYSURF is the surface you are drawing the rectangle on.<br />
BLUE is the colour of the rectangle.<br />
boxx / boxy is the start co-ordinate in x/y<br />
NUMBERSIZE/NUMBERSIZE is not the co-ordinates for the end of the box, but the size of the box in x/y.<br />
Notice the use of brackets around the previous 4 items.<br />
Finally the 1 signifies the width of the line you would like to draw.<br />
<br />
I have stated we want the box to be BLUE. We better add a blue colour to our colour global variables at the top of the program.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;"># Set up the colours</span>
<span class="n">BLACK</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span> <span class="p">,</span><span class="mi" style="color: #40a070;">0</span> <span class="p">,</span><span class="mi" style="color: #40a070;">0</span> <span class="p">)</span>
<span class="n">WHITE</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">)</span>
<span class="n">LIGHTGRAY</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">200</span><span class="p">,</span><span class="mi" style="color: #40a070;">200</span><span class="p">,</span><span class="mi" style="color: #40a070;">200</span><span class="p">)</span>
<span class="n">BLUE</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span> <span class="p">,</span><span class="mi" style="color: #40a070;">0</span> <span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">)</span></pre>
Ok that's this stage finished! If you run the program and move your mouse over the grid you should see a blue box around the number your mouse is hovering over. As you click on the number do you notice the co-ordinates are printed out in the shell?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAUXXxhRyGnnShWXuBu1Kxx_ezmAgh2AX2DSfU6dGl9jKK1-My2qmB7BntyR19yBIeJXbrza6oQUH98sJ6wFkfwtehQPEHjeZ3BtglvYE84cHPRuXpGMnRiAaZ2P02xJZi9pHj68Tnq28/s1600/Sudoku_Co-ords_in_Shell.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="204" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAUXXxhRyGnnShWXuBu1Kxx_ezmAgh2AX2DSfU6dGl9jKK1-My2qmB7BntyR19yBIeJXbrza6oQUH98sJ6wFkfwtehQPEHjeZ3BtglvYE84cHPRuXpGMnRiAaZ2P02xJZi9pHj68Tnq28/s320/Sudoku_Co-ords_in_Shell.PNG" width="320" /></a></div>
<br />
<br />
<a href="https://docs.google.com/file/d/0B87aGq7vEpoFRjZyM0dJXzFXY00/edit?usp=sharing" target="_blank">Sudoku Step 4 Source Code</a><br />
<br />
<b>Step 5 - Update the screen as numbers are selected</b><br />
<br />
The purpose of this section is to take the location of the mouse as its button is clicked and use it to select that number in the grid.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgoKpkzcJWPnyTyMOw5iBilejKc9OLSTggPq8_zbz6bBNETDMqec636MTVlK0_fvy6k25iWqN6uVx5oO7_DIbnfotQxJtGaMVe6r_YgB0wlHSrNhBoygQ5yKFNks7goYT6_WP19JKJW-E/s1600/SudokuSolver_Step5.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgoKpkzcJWPnyTyMOw5iBilejKc9OLSTggPq8_zbz6bBNETDMqec636MTVlK0_fvy6k25iWqN6uVx5oO7_DIbnfotQxJtGaMVe6r_YgB0wlHSrNhBoygQ5yKFNks7goYT6_WP19JKJW-E/s320/SudokuSolver_Step5.PNG" width="307" /></a></div>
<br />
In the previous section we drew a square around the number the mouse was currently over, and when the mouse was clicked we reported back the co-ordinates of its location. If you remember back to earlier in our program we stated that each cell had 9 numbers (1-9) which could be selected. These could reduce in number by some numbers becoming a space to signify these were no longer an option ' '. These will reduce as the Sudoku is solved. If the user were to click on a number, it would mean that number has been selected as right. Therefore all other numbers in that cell can be eliminated i.e. made into a space ' '.<br />
<br />
First things first. To display the number we have selected we will display it as green. Therefore add a GREEN to your list of global variables.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;"># Set up the colours</span>
<span class="n">BLACK</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span> <span class="p">,</span><span class="mi" style="color: #40a070;">0</span> <span class="p">,</span><span class="mi" style="color: #40a070;">0</span> <span class="p">)</span>
<span class="n">WHITE</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">)</span>
<span class="n">LIGHTGRAY</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">200</span><span class="p">,</span><span class="mi" style="color: #40a070;">200</span><span class="p">,</span><span class="mi" style="color: #40a070;">200</span><span class="p">)</span>
<span class="n">BLUE</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span> <span class="p">,</span><span class="mi" style="color: #40a070;">0</span> <span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">)</span>
<span class="n">GREEN</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span> <span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span> <span class="p">)</span></pre>
Whereas the current font takes up a 1/9 of the cell we will also want to display a larger font to take up the whole of the cell. So add a large font to the location where you define the BASICFONT.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">global</span> <span class="n">BASICFONT</span><span class="p">,</span> <span class="n">BASICFONTSIZE</span><span class="p">,</span> <span class="n">LARGEFONT</span><span class="p">,</span> <span class="n">LARGEFONTSIZE</span>
<span class="n">BASICFONTSIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">15</span>
<span class="n">LARGEFONTSIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">55</span>
<span class="n">BASICFONT</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">font</span><span class="o" style="color: #666666;">.</span><span class="n">Font</span><span class="p">(</span><span class="s" style="color: #4070a0;">'freesansbold.ttf'</span><span class="p">,</span> <span class="n">BASICFONTSIZE</span><span class="p">)</span>
<span class="n">LARGEFONT</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">font</span><span class="o" style="color: #666666;">.</span><span class="n">Font</span><span class="p">(</span><span class="s" style="color: #4070a0;">'freesansbold.ttf'</span><span class="p">,</span> <span class="n">LARGEFONTSIZE</span><span class="p">)</span></pre>
</pre>
At the moment when we click the mouse we print out the position of x and y. Lets change this so it calls a function called displaySelectedNumber<br />
<br />
So replace the print statements with a call to the function.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">mouseClicked</span> <span class="o" style="color: #666666;">==</span> <span class="bp" style="color: #007020;">True</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">mousex</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="n">mousey</span></pre>
Should be replaced with<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">mouseClicked</span> <span class="o" style="color: #666666;">==</span> <span class="bp" style="color: #007020;">True</span><span class="p">:</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># allow number to be selected</span>
<span class="n">currentGrid</span> <span class="o" style="color: #666666;">=</span> <span class="n">displaySelectedNumber</span><span class="p">(</span><span class="n">mousex</span><span class="p">,</span> <span class="n">mousey</span><span class="p">,</span> <span class="n">currentGrid</span><span class="p">)</span></pre>
This function requires the x and y co-ordinates and the state of the current grid. So we are passing that information into the function.<br />
<br />
Now we should write the function displaySelectedNumber. The purpose of this function is to identify the number we have selected and to update the dictionary which holds the information regarding the current state of the grid. Here is the completed function and we will run through it line by line.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">displaySelectedNumber</span><span class="p">(</span><span class="n">mousex</span><span class="p">,</span> <span class="n">mousey</span><span class="p">,</span> <span class="n">currentGrid</span><span class="p">):</span>
<span class="n">xNumber</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">mousex</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #40a070;">27</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span> <span class="n">WINDOWWIDTH</span> <span class="c" style="color: #60a0b0; font-style: italic;"># xNumber in range 0 - 26</span>
<span class="n">yNumber</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">mousey</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #40a070;">27</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span> <span class="n">WINDOWWIDTH</span> <span class="c" style="color: #60a0b0; font-style: italic;"># yNumber in range 0 - 26</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Determine a 0,1 or 2 for x and y</span>
<span class="n">modXNumber</span> <span class="o" style="color: #666666;">=</span> <span class="n">xNumber</span> <span class="o" style="color: #666666;">%</span> <span class="mi" style="color: #40a070;">3</span>
<span class="n">modYNumber</span> <span class="o" style="color: #666666;">=</span> <span class="n">yNumber</span> <span class="o" style="color: #666666;">%</span> <span class="mi" style="color: #40a070;">3</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">modXNumber</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">0</span><span class="p">:</span>
<span class="n">xChoices</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">7</span><span class="p">]</span>
<span class="n">number</span> <span class="o" style="color: #666666;">=</span> <span class="n">xChoices</span><span class="p">[</span><span class="n">modYNumber</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">modXNumber</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="n">xChoices</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">8</span><span class="p">]</span>
<span class="n">number</span> <span class="o" style="color: #666666;">=</span> <span class="n">xChoices</span><span class="p">[</span><span class="n">modYNumber</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">xChoices</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">9</span><span class="p">]</span>
<span class="n">number</span> <span class="o" style="color: #666666;">=</span> <span class="n">xChoices</span><span class="p">[</span><span class="n">modYNumber</span><span class="p">]</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># need to determine the cell we are in</span>
<span class="n">xCellNumber</span> <span class="o" style="color: #666666;">=</span> <span class="n">xNumber</span> <span class="o" style="color: #666666;">/</span> <span class="mi" style="color: #40a070;">3</span>
<span class="n">yCellNumber</span> <span class="o" style="color: #666666;">=</span> <span class="n">yNumber</span> <span class="o" style="color: #666666;">/</span> <span class="mi" style="color: #40a070;">3</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># gets a list of current numbers</span>
<span class="n">currentState</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGrid</span><span class="p">[</span><span class="n">xCellNumber</span><span class="p">,</span><span class="n">yCellNumber</span><span class="p">]</span>
<span class="n">incNum</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="k" style="color: #007020; font-weight: bold;">while</span> <span class="n">incNum</span> <span class="o" style="color: #666666;"><</span> <span class="mi" style="color: #40a070;">9</span><span class="p">:</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># if NOT number selected</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">incNum</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">1</span> <span class="o" style="color: #666666;">!=</span> <span class="n">number</span><span class="p">:</span>
<span class="n">currentState</span><span class="p">[</span><span class="n">incNum</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">' '</span> <span class="c" style="color: #60a0b0; font-style: italic;"># make ' '</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">currentState</span><span class="p">[</span><span class="n">incNum</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">number</span> <span class="c" style="color: #60a0b0; font-style: italic;"># make = number</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#update currentGrid</span>
<span class="n">currentGrid</span><span class="p">[</span><span class="n">xCellNumber</span><span class="p">,</span><span class="n">yCellNumber</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentState</span>
<span class="n">incNum</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGrid</span></pre>
The first part of the function is to identify the number we have chosen.<br />
<br />
The first line is obviously stating the function name, and the fact it is expecting mousex, mousey and currentGrid to be passed into it.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">displaySelectedNumber</span><span class="p">(</span><span class="n">mousex</span><span class="p">,</span> <span class="n">mousey</span><span class="p">,</span> <span class="n">currentGrid</span><span class="p">):</span></pre>
The next two lines<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">xNumber</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">mousex</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #40a070;">27</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span> <span class="n">WINDOWWIDTH</span> <span class="c" style="color: #60a0b0; font-style: italic;"># xNumber in range 0 - 26</span>
<span class="n">yNumber</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">mousey</span><span class="o" style="color: #666666;">*</span><span class="mi" style="color: #40a070;">27</span><span class="p">)</span> <span class="o" style="color: #666666;">/</span> <span class="n">WINDOWWIDTH</span> <span class="c" style="color: #60a0b0; font-style: italic;"># yNumber in range 0 - 26</span></pre>
return a number from 0 - 26, which is 27 numbers, to cover all the potential numbers in cells in x and y. It is a similar function to the function we used in the drawBox function to determine boxx and boxy. However we are only interested in which number we have selected and not its location, so we don't need to multiply by NUMBERSIZE.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;">#Determine a 0,1 or 2 for x and y</span>
<span class="n">modXNumber</span> <span class="o" style="color: #666666;">=</span> <span class="n">xNumber</span> <span class="o" style="color: #666666;">%</span> <span class="mi" style="color: #40a070;">3</span>
<span class="n">modYNumber</span> <span class="o" style="color: #666666;">=</span> <span class="n">yNumber</span> <span class="o" style="color: #666666;">%</span> <span class="mi" style="color: #40a070;">3</span></pre>
These two lines take the modulus of the numbers (from 0-26) which we have just determined. This will store either a 0,1 or a 2 depending on the result of the modulus. This is carried out for the x and y axis. The two numbers modXNumber and modYNumber are in effect co-ordintes to determine which number in the cell we have chosen. Remember the numbers are in the format<br />
<br />
123<br />
456<br />
789<br />
<br />
The next few lines cover an if ... else statement. These help determine which number has been clicked on. We have carried out a similar process in our displayCells function. However in that function we only needed to determine the co-ordinates of the number within a cell. Now we need to determine the actual number we have clicked on no matter where we clicked in the screen.<br />
<br />
The results for modXNumber for various xNumbers will be<br />
<br />
0 % 3 = 0<br />
1 % 3 = 1<br />
2 % 3 = 2<br />
3 % 3 = 0<br />
4 % 3 = 1<br />
5 % 3 = 2<br />
<br />
etc etc<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">modXNumber</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">0</span><span class="p">:</span>
<span class="n">xChoices</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">7</span><span class="p">]</span>
<span class="n">number</span> <span class="o" style="color: #666666;">=</span> <span class="n">xChoices</span><span class="p">[</span><span class="n">modYNumber</span><span class="p">]</span> </pre>
The if statement says that if the modXNumber is 0, then the options can be narrowed down to a 1,4 or a 7. We store these in a list called xChoices.<br />
<br />
So we have sorted out which column we are in, what about the row? Well we have modYNumber. Again the result of yNumber % 3 will be 0,1,2,0,1,2 etc as shown above. We know if modYNumber is 0 then the number has to be in the top row (1,2 or 3). If its a 1 it will be in the middle row (4,5 or 6) or a 2 in the bottom row(7,8 or 9).<br />
<br />
But we have already used modXNumber to narrow down the options so there is one potential number from the top row, one from the middle and one from the bottom. There are stored in a list with the top row in the 1st position i.e. xChoices[0]<br />
<br />
Therefore the line<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">number</span> <span class="o" style="color: #666666;">=</span> <span class="n">xChoices</span><span class="p">[</span><span class="n">modYNumber</span><span class="p">]</span> </pre>
uses modYNumber to determine which number from the list we are interested in. Which will be the number we clicked on.<br />
<br />
The remainder of the If... Else statement covers the other rows<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">modXNumber</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="n">xChoices</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">8</span><span class="p">]</span>
<span class="n">number</span> <span class="o" style="color: #666666;">=</span> <span class="n">xChoices</span><span class="p">[</span><span class="n">modYNumber</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">xChoices</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">9</span><span class="p">]</span>
<span class="n">number</span> <span class="o" style="color: #666666;">=</span> <span class="n">xChoices</span><span class="p">[</span><span class="n">modYNumber</span><span class="p">]</span></pre>
So we have completed the first part of the function and determined which number we have clicked on.<br />
<br />
Now lets determine which cell we are in.<br />
<br />
The first two lines in this function told us with of the 27 potential numbers in x we had clicked on and the same for y. Each cell has three numbers, so if we divide the number we have clicked on by three this will give us which cell we are in.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;"># need to determine the cell we are in</span>
<span class="n">xCellNumber</span> <span class="o" style="color: #666666;">=</span> <span class="n">xNumber</span> <span class="o" style="color: #666666;">/</span> <span class="mi" style="color: #40a070;">3</span>
<span class="n">yCellNumber</span> <span class="o" style="color: #666666;">=</span> <span class="n">yNumber</span> <span class="o" style="color: #666666;">/</span> <span class="mi" style="color: #40a070;">3</span></pre>
Now we will interrogate that cell and check what numbers are currently stored in there. We will store the numbers in a list called currentState using the line<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;"># gets a list of current numbers</span>
<span class="n">currentState</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGrid</span><span class="p">[</span><span class="n">xCellNumber</span><span class="p">,</span><span class="n">yCellNumber</span><span class="p">]</span></pre>
What we are going to do now is go through each of the numbers in the cell. If its not the number we have picked, we will set it to a space ' '. If it is the number we have chosen, that becomes the only remaining number in the list for that cell.<br />
<br />
First of all we create a number to increment each time, called incNum and set this to 0. We will increase this each time and check if it matches against the number we picked. This will also help us identify which item in the list we can set to ' '.<br />
<br />
First the number we will increment each time.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">incNum</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span></pre>
Now we start a while loop which will run through the numbers 0 - 8.<br />
<br />
The next two lines<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;"># if NOT number selected</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">incNum</span><span class="o" style="color: #666666;">+</span><span class="mi" style="color: #40a070;">1</span> <span class="o" style="color: #666666;">!=</span> <span class="n">number</span><span class="p">:</span>
<span class="n">currentState</span><span class="p">[</span><span class="n">incNum</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">' '</span> <span class="c" style="color: #60a0b0; font-style: italic;"># make ' '</span></pre>
States if the incNum + 1 is not equal to the number (inc runs from 0-8, our numbers 1-9, so we need to add 1 to it) we have selected, we should make that number in the list a space ' '.<br />
We then say else, which covers all cases where they are the same.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">currentState</span><span class="p">[</span><span class="n">incNum</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">number</span> <span class="c" style="color: #60a0b0; font-style: italic;"># make = number</span></pre>
Perfect, there should only be one number, the one we have chosen, in the currentState list.<br />
<br />
Lets then update the dictionary, currentGrid with this information<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;">#update currentGrid</span>
<span class="n">currentGrid</span><span class="p">[</span><span class="n">xCellNumber</span><span class="p">,</span><span class="n">yCellNumber</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentState</span></pre>
And finally don't forget to increase incNum, or else we will be stuck in the while loop forever.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">incNum</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span></pre>
Until returning the currentGrid<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGrid</span></pre>
Before running your program there is just one thing left to do. In our populateCells function which draws the numbers in the grid, all the numbers are defined as having the same size / colour font. We have not used our new larger font yet. How can we tell if the font should be large or small? Well if there in only one number, and 8 spaces in that cell, then the number should use the large font, otherwise it should still be on the small font.<br />
<br />
In our displayCells function change the line which calls the populateCells function from<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;">#(item[0] * CELLSIZE) Positions in the right Cell</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#(xFactor*NUMBERSIZE) Offsets to position number </span>
<span class="n">populateCells</span><span class="p">(</span><span class="n">number</span><span class="p">,(</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">*</span><span class="n">CELLSIZE</span><span class="p">)</span><span class="o" style="color: #666666;">+</span><span class="p">(</span><span class="n">xFactor</span><span class="o" style="color: #666666;">*</span><span class="n">NUMBERSIZE</span><span class="p">),(</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">*</span><span class="n">CELLSIZE</span><span class="p">)</span><span class="o" style="color: #666666;">+</span><span class="p">(</span><span class="n">yFactor</span><span class="o" style="color: #666666;">*</span><span class="n">NUMBERSIZE</span><span class="p">))</span></pre>
to<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;">#(item[0] * CELLSIZE) Positions in the right Cell</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#(xFactor*NUMBERSIZE) Offsets to position number</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">cellData</span><span class="o" style="color: #666666;">.</span><span class="n">count</span><span class="p">(</span><span class="s" style="color: #4070a0;">' '</span><span class="p">)</span> <span class="o" style="color: #666666;"><</span> <span class="mi" style="color: #40a070;">8</span><span class="p">:</span>
<span class="n">populateCells</span><span class="p">(</span><span class="n">number</span><span class="p">,(</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">*</span><span class="n">CELLSIZE</span><span class="p">)</span><span class="o" style="color: #666666;">+</span><span class="p">(</span><span class="n">xFactor</span><span class="o" style="color: #666666;">*</span><span class="n">NUMBERSIZE</span><span class="p">),(</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">*</span><span class="n">CELLSIZE</span><span class="p">)</span><span class="o" style="color: #666666;">+</span><span class="p">(</span><span class="n">yFactor</span><span class="o" style="color: #666666;">*</span><span class="n">NUMBERSIZE</span><span class="p">),</span><span class="s" style="color: #4070a0;">'small'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">populateCells</span><span class="p">(</span><span class="n">number</span><span class="p">,(</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">*</span><span class="n">CELLSIZE</span><span class="p">),(</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">*</span><span class="n">CELLSIZE</span><span class="p">),</span><span class="s" style="color: #4070a0;">'large'</span><span class="p">)</span></pre>
As before this calls the populate cells, but differentiates if there in only a single number remaining, meaning the large font should be used, or multiple numbers, meaning the small font should be used. It checks this by using the line<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">cellData</span><span class="o" style="color: #666666;">.</span><span class="n">count</span><span class="p">(</span><span class="s" style="color: #4070a0;">' '</span><span class="p">)</span> <span class="o" style="color: #666666;"><</span> <span class="mi" style="color: #40a070;">8</span><span class="p">:</span> </pre>
Which counts the number of spaces, a very useful command!<br />
<br />
Now both options call the populateCells, but they also send a string saying 'small' or 'large' to the function, so lets modify that function to accept this.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;"># writes cellData at given x, y co-ordinates </span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">populateCells</span><span class="p">(</span><span class="n">cellData</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span><span class="n">size</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">size</span> <span class="o" style="color: #666666;">==</span> <span class="s" style="color: #4070a0;">'small'</span><span class="p">:</span>
<span class="n">cellSurf</span> <span class="o" style="color: #666666;">=</span> <span class="n">BASICFONT</span><span class="o" style="color: #666666;">.</span><span class="n">render</span><span class="p">(</span><span class="s" style="color: #4070a0;">'</span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">'</span> <span class="o" style="color: #666666;">%</span><span class="p">(</span><span class="n">cellData</span><span class="p">),</span> <span class="bp" style="color: #007020;">True</span><span class="p">,</span> <span class="n">LIGHTGRAY</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">size</span> <span class="o" style="color: #666666;">==</span> <span class="s" style="color: #4070a0;">'large'</span><span class="p">:</span>
<span class="n">cellSurf</span> <span class="o" style="color: #666666;">=</span> <span class="n">LARGEFONT</span><span class="o" style="color: #666666;">.</span><span class="n">render</span><span class="p">(</span><span class="s" style="color: #4070a0;">'</span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">'</span> <span class="o" style="color: #666666;">%</span><span class="p">(</span><span class="n">cellData</span><span class="p">),</span> <span class="bp" style="color: #007020;">True</span><span class="p">,</span> <span class="n">GREEN</span><span class="p">)</span>
<span class="n">cellRect</span> <span class="o" style="color: #666666;">=</span> <span class="n">cellSurf</span><span class="o" style="color: #666666;">.</span><span class="n">get_rect</span><span class="p">()</span>
<span class="n">cellRect</span><span class="o" style="color: #666666;">.</span><span class="n">topleft</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">blit</span><span class="p">(</span><span class="n">cellSurf</span><span class="p">,</span> <span class="n">cellRect</span><span class="p">)</span></pre>
The first change is to the header so also accept size.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">populateCells</span><span class="p">(</span><span class="n">cellData</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span><span class="n">size</span><span class="p">):</span></pre>
We then change the cellSurf depending on which font we are using. The rest of the function can remain the same.<br />
<br />
It's time to test your program out. Save and run your program and see what clicking on different cells achieves. Hopefully you will get a similar result to the picture at the top of this section!<br />
<br />
<a href="https://docs.google.com/file/d/0B87aGq7vEpoFQTc2MmZSeUhqbWs/edit?usp=sharing" target="_blank">Sudoku Step 5 Source Code</a><br />
<br />
<b>Step 6 - Implement the first method of solving Sudoku</b><br />
<b><br /></b>
Most of the hard work has been done, so now we can get on with the fun part of writing some algorithms to solve the Sudoku! The first thing we will do is to ensure when a number is clicked on, and selected, that number becomes unavailable for all other cells in the same Row, Column, and group of 9 cells that make a larger square.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEib48-QE6KMXgfoEjiBpMtykD68aS7WldAFK1j6tfd5b613WtlR65pMc7X87qR_cRq75XX27AtRThAxRcJeW8Z9Dtja__3h3uTXOrdZbbKBQa016Ch4OMK3npy0MHSpBVVCQh2dxv25M5M/s1600/Sudoku+-+Step6.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEib48-QE6KMXgfoEjiBpMtykD68aS7WldAFK1j6tfd5b613WtlR65pMc7X87qR_cRq75XX27AtRThAxRcJeW8Z9Dtja__3h3uTXOrdZbbKBQa016Ch4OMK3npy0MHSpBVVCQh2dxv25M5M/s320/Sudoku+-+Step6.PNG" width="307" /></a></div>
<br />
Let's link to all our Sudoku Solving algorithms in one function called solveSudoku. The first thing we will need to do then is call our solveSudoku function from our main function.<br />
<br />
We want to ensure this is called from within our loop, so it is checked continuously, therefore place a call to this function under the mouseClicked == True section as shown below.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">mouseClicked</span> <span class="o" style="color: #666666;">==</span> <span class="bp" style="color: #007020;">True</span><span class="p">:</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># allow number to be selected</span>
<span class="n">currentGrid</span> <span class="o" style="color: #666666;">=</span> <span class="n">displaySelectedNumber</span><span class="p">(</span><span class="n">mousex</span><span class="p">,</span> <span class="n">mousey</span><span class="p">,</span> <span class="n">currentGrid</span><span class="p">)</span>
<span class="n">solveSudoku</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">)</span></pre>
Lets go and write the new function below all the other functions we have written. Here is the function with a description to follow.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">solveSudoku</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentGrid</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;"># item is x,y co-ordinate from 0-8</span>
<span class="n">cellData</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGrid</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="c" style="color: #60a0b0; font-style: italic;"># isolates the numbers still available for that cell</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">cellData</span><span class="o" style="color: #666666;">.</span><span class="n">count</span><span class="p">(</span><span class="s" style="color: #4070a0;">' '</span><span class="p">)</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">8</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;"># only look at those with one number remaining</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">number</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">cellData</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;"># Determine the number there</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">number</span> <span class="o" style="color: #666666;">!=</span> <span class="s" style="color: #4070a0;">' '</span><span class="p">:</span>
<span class="n">updateNumber</span> <span class="o" style="color: #666666;">=</span> <span class="n">number</span>
<span class="n">currentGrid</span> <span class="o" style="color: #666666;">=</span> <span class="n">removeX</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="n">updateNumber</span><span class="p">)</span>
<span class="n">currentGrid</span> <span class="o" style="color: #666666;">=</span> <span class="n">removeY</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="n">updateNumber</span><span class="p">)</span>
<span class="n">currentGrid</span> <span class="o" style="color: #666666;">=</span> <span class="n">removeGrid</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="n">updateNumber</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGrid</span></pre>
</pre>
The first line is defining the name of the function and tells the function that we are passing currentGrid into it.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">solveSudoku</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">):</span></pre>
We then go into a for loop, which runs through each of the items in the currentGrid dictionary.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentGrid</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;"># item is x,y co-ordinate from 0-8</span>
</pre>
<div>
However this runs through the keys and not the values, so for each cell lets look at what numbers are still available in that cell.</div>
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">cellData</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGrid</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="c" style="color: #60a0b0; font-style: italic;"># isolates the numbers still available for that cell</span></pre>
The next line looks at the cells which only have one number remaining. We can only start to remove numbers from the other cells if we have a cell with only one number in it.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">cellData</span><span class="o" style="color: #666666;">.</span><span class="n">count</span><span class="p">(</span><span class="s" style="color: #4070a0;">' '</span><span class="p">)</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">8</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;"># only look at those with one number remaining</span></pre>
We have used this line before to count the number of spaces left in our list, if there are 8 spaces there must only be one number remaining.<br />
<br />
Now we know there is only one number left the next three lines work out which number is left and stores that number in a variable called updateNumber.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">number</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">cellData</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;"># Determine the number there</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">number</span> <span class="o" style="color: #666666;">!=</span> <span class="s" style="color: #4070a0;">' '</span><span class="p">:</span>
<span class="n">updateNumber</span> <span class="o" style="color: #666666;">=</span> <span class="n">number</span></pre>
Now we have isolated a cell with a single number in there, and have stored that single number, we can now check to see if any of the other cells in the same row, column or square (3x3 cells separated by the darker lines) have that number in, and if so we can remove it from their list of potential numbers.<br />
<br />
We will have to employ different methods for checking the row, the column and the square, so lets write a separate function for each of these three.<br />
<br />
The next three lines call the three separate functions one at a time. For each of the functions currentGrid, item and updateNumber are passed into the functions. As these update the grid we will take the result from each of the functions and make currentGrid equal to what we return. These are followed by the return statement.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"> <span class="n">currentGrid</span> <span class="o" style="color: #666666;">=</span> <span class="n">removeX</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="n">updateNumber</span><span class="p">)</span>
<span class="n">currentGrid</span> <span class="o" style="color: #666666;">=</span> <span class="n">removeY</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="n">updateNumber</span><span class="p">)</span>
<span class="n">currentGrid</span> <span class="o" style="color: #666666;">=</span> <span class="n">removeGrid</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="n">updateNumber</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGrid</span></pre>
</pre>
Let us start by writing the removeX function. This looks at all the other cells in the same row as the cell we know only has one number, and removes that number from each of them.<br />
<br />
We should write this function below the solveSudoku function.<br />
<br />
Here is the function in its entirety, with a line by line explanation following.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">removeX</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="n">number</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">9</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">x</span> <span class="o" style="color: #666666;">!=</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]:</span>
<span class="n">currentState</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGrid</span><span class="p">[(</span><span class="n">x</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">])]</span>
<span class="n">currentState</span><span class="p">[</span><span class="n">number</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">' '</span>
<span class="n">currentGrid</span><span class="p">[(</span><span class="n">x</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">])]</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentState</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGrid</span></pre>
The first line is defining the name of the function and the data we are passing into the function. currentGrid which shows the state of the whole grid, the item, which is the individual cell we are looking at which only has one number in it, and the number itself.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">removeX</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="n">number</span><span class="p">):</span></pre>
Now we want to run through the numbers 0-8. We know there are 9 cells in the x axis, so if we know the cell we are currently in we can quickly work out the other cells we need to modify.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">9</span><span class="p">):</span></pre>
We know the cell we passed into the function only has one number, so we do not need to modify that. The next line ignores our current cell.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">x</span> <span class="o" style="color: #666666;">!=</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]:</span>
</pre>
<div>
<span class="p">For each of the cells in the same row, we copy the list of numbers from that cell into a variable called currentState</span></div>
<div>
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="p"> <span class="n">currentState</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGrid</span><span class="p">[(</span><span class="n">x</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">])]</span></span></pre>
<span class="p">
</span></div>
We determine the data we are copying based on the dictionary key determined by (x,item[1]). The x value is provided by the for x in range (0,9) command. This iterates through the numbers 0-8 inclusive. The y data is from item[1], which is the y component of the co-ordinate from the item we looking at. As we want to only look at one row then the y value will be the same for all 9 items we look at.<br />
<br />
We then modify the currentState list, replacing the number we know should not be in the list by a space. <br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">currentState</span><span class="p">[</span><span class="n">number</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">' '</span></pre>
Remember when looking at a list the first number in the list is list[0], that is why we have to minus 1 from the number. The first number in our list is a 1, which is in position 0 in the list.<br />
<br />
We then update the information in our dictionary to reflect the changes we have made.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">currentGrid</span><span class="p">[(</span><span class="n">x</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">])]</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentState</span></pre>
Then we return the data in currentGrid which has the updated version of the Sudoku grid.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGrid</span></pre>
We now write the create removeY function. This now looks at all the other cells in the same column as the cell we know only has one number, and removes that number from each of them.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">removeY</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="n">number</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">y</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">9</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">y</span> <span class="o" style="color: #666666;">!=</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]:</span>
<span class="n">currentState</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGrid</span><span class="p">[(</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">],</span><span class="n">y</span><span class="p">)]</span>
<span class="n">currentState</span><span class="p">[</span><span class="n">number</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">' '</span>
<span class="n">currentGrid</span><span class="p">[(</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">],</span><span class="n">y</span><span class="p">)]</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentState</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGrid</span></pre>
The function removeY is very similar to removeX. However this time we know the column we want to look at and modify so the x value, defined by item[0], stays the same, but we iterate through different y values to allow us to modify the whole column.<br />
<br />
Finally we have to look at modifying all the items in the same square. The square is one of the 9 larger squares in a Sudoku made up of nine smaller squares. This is a little more complex so will need some explanation. While the principle is the same a little more work has to be done to determine which cells need modification. The function is as follows.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">removeGrid</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="n">number</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;"><</span> <span class="mi" style="color: #40a070;">3</span><span class="p">:</span>
<span class="n">xGrid</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">></span> <span class="mi" style="color: #40a070;">5</span><span class="p">:</span>
<span class="n">xGrid</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">7</span><span class="p">,</span><span class="mi" style="color: #40a070;">8</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span> <span class="n">xGrid</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;"><</span> <span class="mi" style="color: #40a070;">3</span><span class="p">:</span>
<span class="n">yGrid</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">></span> <span class="mi" style="color: #40a070;">5</span><span class="p">:</span>
<span class="n">yGrid</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">7</span><span class="p">,</span><span class="mi" style="color: #40a070;">8</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span> <span class="n">yGrid</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">]</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#iterates through each of the nine numbers in the grid</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">xGrid</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">y</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">yGrid</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">)</span> <span class="o" style="color: #666666;">!=</span> <span class="n">item</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;"># for all squares except the one containing the number</span>
<span class="n">currentState</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGrid</span><span class="p">[(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">)]</span> <span class="c" style="color: #60a0b0; font-style: italic;"># isolates the numbers still available for that cell</span>
<span class="n">currentState</span><span class="p">[</span><span class="n">number</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">' '</span> <span class="c" style="color: #60a0b0; font-style: italic;"># make them blank.</span>
<span class="n">currentGrid</span><span class="p">[(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">)]</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentState</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGrid</span></pre>
</pre>
The first line obviously defines the name of the function and the variables passed into it.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">removeGrid</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="n">number</span><span class="p">):</span></pre>
We then want to find out the co-ordinates which make up the nine cells defining the larger square we want to modify. Starting with the x values.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;"><</span> <span class="mi" style="color: #40a070;">3</span><span class="p">:</span>
<span class="n">xGrid</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">></span> <span class="mi" style="color: #40a070;">5</span><span class="p">:</span>
<span class="n">xGrid</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">7</span><span class="p">,</span><span class="mi" style="color: #40a070;">8</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span> <span class="n">xGrid</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">]</span>
</pre>
<div>
<span class="p">This code looks at the item we have passed into it. If the x component of the co-ordinate is less than 3, we know we want to modify only items which have x co-ordinates 0,1 or 2 in our 9x9 grid. </span></div>
<div>
<span class="p">If it is greater than 5, we only want to look at items in position 6,7 & 8, which is the last column of larger squares.</span></div>
<div>
<span class="p">Otherwise we know that it must sit in the middle column in 3,4 & 5</span></div>
<div>
<span class="p"><br /></span></div>
<div>
<span class="p">We repeat the process for the y values to determine the row.</span></div>
<div>
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="p"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;"><</span> <span class="mi" style="color: #40a070;">3</span><span class="p">:</span>
<span class="n">yGrid</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">></span> <span class="mi" style="color: #40a070;">5</span><span class="p">:</span>
<span class="n">yGrid</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">7</span><span class="p">,</span><span class="mi" style="color: #40a070;">8</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span> <span class="n">yGrid</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">]</span></span></pre>
<span class="p">
</span></div>
<div>
<span class="p">So the values in xData and yData will now show us the co-ordinates of all the items in the larger square, which we need to modify.</span></div>
<div>
<span class="p"><br /></span></div>
<div>
Its now a case of iterating through each of these using a loop within a loop, so we run through all 9 cells within the square. </div>
<div>
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">xGrid</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">y</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">yGrid</span></pre>
</div>
<div>
We check to make sure that as we iterate through the cells we ignore the cell which we are investigating.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">)</span> <span class="o" style="color: #666666;">!=</span> <span class="n">item</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;"># for all squares except the one containing the number </span></pre>
For each cell iteration we store the numbers available in a list called currentState.</div>
<div>
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">currentState</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGrid</span><span class="p">[(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">)]</span> <span class="c" style="color: #60a0b0; font-style: italic;"># isolates the numbers still available for that cell</span></pre>
As with the removeX and removeY functions we change the number we are trying to remove from the cell and replace it with a ' ' .</div>
<div>
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">currentState</span><span class="p">[</span><span class="n">number</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">' '</span></pre>
<span class="s">Then we update the information in the dictionary to reflect the changes we have just made</span><br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">currentGrid</span><span class="p">[(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">)]</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentState</span></pre>
<span class="s">Then we return the modified dictionary. </span><br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGrid</span></pre>
<span class="s">Press F5 to save and run the program and have a good click around to ensure the program does what you expect it to. By clicking on a number 5 for instance all the number 5's in the row, column and the square are also removed, which is perfect...</span><br />
<span class="s"><br /></span>
<span class="s"><a href="https://docs.google.com/file/d/0B87aGq7vEpoFTFBudHBYV0RTR3c/edit?usp=sharing" target="_blank">Sudoku Step 6 Source Code</a></span><br />
<span class="s"><br /></span>
<span class="s"><b>Step 7 - Allowing correction of mistakes</b></span><br />
<span class="s"><br /></span>
<span class="s"> however it's not... </span><br />
<span class="s"><br /></span>
<span class="s">What if we were to change our mind? Say we clicked on a 5 by error, and then in the same square we clicked on the location where there should be a 6. We see that all the 5's disappear from the same row, column and square as expected. When we click on where the 6 should be, all the 6's disappear. But the 5's should re-appear. But they don't. By changing our mind we should have only selected one number, but the history of the first number we clicked on is still reflected in our grid. The purpose of this stage is to correct that before we implement any more Sudoku solving algorithms.</span><br />
<span class="s"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9qmUm6q01AScYo70Qo0LQ-1Elx558bnvZg3dVbr5i8SWckdgOPLRLNc3BbdVCwUcXWBQc043goSHprboO1b1dPwYU-ML6gGnBkv6XtpWiR4qOdu_4NmGw8Qjny7mY-2ICgUEfUeACGZQ/s1600/Sudoku-Step7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9qmUm6q01AScYo70Qo0LQ-1Elx558bnvZg3dVbr5i8SWckdgOPLRLNc3BbdVCwUcXWBQc043goSHprboO1b1dPwYU-ML6gGnBkv6XtpWiR4qOdu_4NmGw8Qjny7mY-2ICgUEfUeACGZQ/s320/Sudoku-Step7.png" width="305" /></a></div>
<br />
We know from earlier in our program that when we click the mouse we call the function displaySelectedNumber(). We also know that the program is continuously looping through the main function, and within that function it is calling other functions including solveSudoku(). solveSudoku() looks to see what cells are known and solves all other cells depending on that information.<br />
<br />
If after a mouse click we give displaySelectedNumber() a chance to modify the cells to match our latest click, and then call a function to reset all cells which were not solved (i.e. had more than one potential number remaining) so they once again have all 9 numbers available. When our program gets back to the main loop it would then run solveSudoku(), and all cells would be updated to reflect the cells which are resolved to only having one number.<br />
<br />
Lets program that.<br />
<br />
First thing is we want to give the function displaySelectedNumber() a chance to do its thing. We also know displaySelectedNumber only runs when a mouse is clicked, which is the only time we would want to be updating the cells to reflect a change. Its obvious there can only be a change when the mouse is clicked.<br />
<br />
So at the end of displaySelectedNumber() add the following line just before the return statement.<br />
<span style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; white-space: pre;"> </span><span class="n" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; white-space: pre;">incNum</span><span style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; white-space: pre;"> </span><span class="o" style="color: #666666; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; white-space: pre;">+=</span><span style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; white-space: pre;"> </span><span class="mi" style="color: #40a070; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; white-space: pre;">1</span><br />
<span style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; white-space: pre;"> </span><span class="n" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; white-space: pre;">currentGrid</span><span style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; white-space: pre;"> </span><span class="o" style="color: #666666; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; white-space: pre;">=</span><span style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; white-space: pre;"> </span><span class="n" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; white-space: pre;">refreshGrid</span><span class="p" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; white-space: pre;">(</span><span class="n" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; white-space: pre;">currentGrid</span><span class="p" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; white-space: pre;">)</span><span style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; white-space: pre;">
</span><span class="k" style="color: #007020; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; font-weight: bold; white-space: pre;">return</span><span style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; white-space: pre;"> </span><span class="n" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; white-space: pre;">currentGrid</span><br />
Now below this function we will write the refreshGrid function. Obviously passing currentGrid into it as we will want to be updating this dictionary.<br />
<br />
The function in its entirety is as follows.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;"># If a number is selected, and then changed the grid needs to be refreshed. </span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">refreshGrid</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">):</span>
<span class="n">fullCell</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">7</span><span class="p">,</span><span class="mi" style="color: #40a070;">8</span><span class="p">,</span><span class="mi" style="color: #40a070;">9</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">xCoord</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">9</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">yCoord</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">9</span><span class="p">):</span>
<span class="n">cellData</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGrid</span><span class="p">[</span><span class="n">xCoord</span><span class="p">,</span> <span class="n">yCoord</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">cellData</span><span class="o" style="color: #666666;">.</span><span class="n">count</span><span class="p">(</span><span class="s" style="color: #4070a0;">' '</span><span class="p">)</span> <span class="o" style="color: #666666;"><</span> <span class="mi" style="color: #40a070;">8</span><span class="p">:</span>
<span class="n">currentGrid</span><span class="p">[</span><span class="n">xCoord</span><span class="p">,</span><span class="n">yCoord</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">list</span><span class="p">(</span><span class="n">fullCell</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;"># Copies List</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGrid</span></pre>
After declaring the function name, and stating that we are passing currentGrid into the function, a list is created which holds the information we will use to reset the cell.<br />
<span class="k" style="color: #007020; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; font-weight: bold;">def</span><span style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;"> </span><span class="nf" style="color: #06287e; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">refreshGrid</span><span class="p" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">(</span><span class="n" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">currentGrid</span><span class="p" style="font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px;">):</span><br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">fullCell</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">,</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">7</span><span class="p">,</span><span class="mi" style="color: #40a070;">8</span><span class="p">,</span><span class="mi" style="color: #40a070;">9</span><span class="p">]</span></pre>
Now we iterate through all the cells using the next two lines.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">xCoord</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">9</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">yCoord</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">9</span><span class="p">):</span></pre>
Then take the value from the currentGrid dictionary matching the key[xCoords, yCoord], and store it in the variable cellData<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">cellData</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGrid</span><span class="p">[</span><span class="n">xCoord</span><span class="p">,</span> <span class="n">yCoord</span><span class="p">]</span></pre>
If cellData has less than 8 spaces in it, i.e. we have not yet singled this list down to a single number.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">cellData</span><span class="o" style="color: #666666;">.</span><span class="n">count</span><span class="p">(</span><span class="s" style="color: #4070a0;">' '</span><span class="p">)</span> <span class="o" style="color: #666666;"><</span> <span class="mi" style="color: #40a070;">8</span><span class="p">:</span></pre>
We reset it by storing the information from fullCell as the value for the key associated with the cell in the dictionary. list fullCell ensures the list is copied.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">currentGrid</span><span class="p">[</span><span class="n">xCoord</span><span class="p">,</span><span class="n">yCoord</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">list</span><span class="p">(</span><span class="n">fullCell</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;"># Copies List</span></pre>
Finally we return the new currentCell<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGrid</span></pre>
Now if you save the program and test it you should see that if you click one number, and then correct it all the other cells update to match the correction.<br />
<br />
<a href="https://docs.google.com/file/d/0B87aGq7vEpoFU2Y1QXo5VFJwQWc/edit?usp=sharing" target="_blank">Sudoku Step 7 Source Code</a><br />
<br />
<b>Step 8 - Implement a second method of solving Sudoku</b><br />
<br />
The final method of solving a Sudoku that we will implement in this blog is to check the rows, column and the squares to see if a number appears in only one of those group of cells. If it does, even if other numbers are still available in that cell, we can discount those and determine the number in the cell is the number that only appears once.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqFJTLCeRnms3aTqM6hnlSNVMn0vaXC6QKH5cR5nYDDvWCBJ6qYPhzXlNLXwv1FYBTddkTykunD9wfjbFNTwLf2lkKqEQGlfwy2ukcSs7NS8OgeKQVkaBF9SEnoq149tEIEx4IuEc7Gt8/s1600/Sudoku_Step8.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqFJTLCeRnms3aTqM6hnlSNVMn0vaXC6QKH5cR5nYDDvWCBJ6qYPhzXlNLXwv1FYBTddkTykunD9wfjbFNTwLf2lkKqEQGlfwy2ukcSs7NS8OgeKQVkaBF9SEnoq149tEIEx4IuEc7Gt8/s320/Sudoku_Step8.PNG" width="299" /></a></div>
Again we will write three functions for this. One function dealing with the rows, one for the column and one checking the squares.<br />
<br />
The first thing we will want to do is to call the three functions which will do the hard work from our solverSudoku function.<br />
<br />
For our previous three solving algorithms explained in step 6 we went through each of the cells in the grid and determined which only had one number in them. We then sent information about that cell, the number and the overall grid into the three solving functions (removeX, removeY & removeGrid). However for this next algorithm we don't want to narrow down the cells, or supply a number. We only want to supply the data in currentGrid, and return it if modified. We will call three functions to check if there is only one number in x (the row), y (the column) or the Square of 9 cells. At the end of the solveSudoku function add the following three lines just before return currentGrid. Note they are not indented like the previous function calls.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;"># determine if any cells contain a number only used once in X/Y/Grid</span>
<span class="n">currentGrid</span> <span class="o" style="color: #666666;">=</span> <span class="n">onlyNinX</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">)</span>
<span class="n">currentGrid</span> <span class="o" style="color: #666666;">=</span> <span class="n">onlyNinY</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">)</span>
<span class="n">currentGrid</span> <span class="o" style="color: #666666;">=</span> <span class="n">onlyNinGrid</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGrid</span></pre>
We will write the onlyNinX(currentGrid) function first of all.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;"># Go through each cell in each row</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># check if it contains a number which is not in the rest of the row.</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">onlyNinX</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">):</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># check all items in currentGrid list</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentGrid</span><span class="p">:</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># create two empty lists</span>
<span class="n">allNumbers</span> <span class="o" style="color: #666666;">=</span> <span class="p">[]</span>
<span class="n">currentNumbers</span> <span class="o" style="color: #666666;">=</span> <span class="p">[]</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># determine all numbers remaining in the row - store in allNumbers</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">xRange</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">9</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">rowNumbers</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentGrid</span><span class="p">[(</span><span class="n">xRange</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">])]:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">rowNumbers</span> <span class="o" style="color: #666666;">!=</span> <span class="s" style="color: #4070a0;">' '</span><span class="p">:</span>
<span class="n">allNumbers</span><span class="o" style="color: #666666;">.</span><span class="n">append</span><span class="p">(</span><span class="n">rowNumbers</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># determine numbers remaining in individual cell being looked at - store in currentNumbers</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">cellNumbers</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentGrid</span><span class="p">[</span><span class="n">item</span><span class="p">]:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">cellNumbers</span> <span class="o" style="color: #666666;">!=</span> <span class="s" style="color: #4070a0;">' '</span><span class="p">:</span>
<span class="n">currentNumbers</span><span class="o" style="color: #666666;">.</span><span class="n">append</span><span class="p">(</span><span class="n">cellNumbers</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;"> </span>
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;"># look at numbers remaining in a cell. Check if they only appear in the row once. </span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="nb" style="color: #007020;">len</span><span class="p">(</span><span class="n">currentNumbers</span><span class="p">)</span> <span class="o" style="color: #666666;">></span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">checkNumber</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentNumbers</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">allNumbers</span><span class="o" style="color: #666666;">.</span><span class="n">count</span><span class="p">(</span><span class="n">checkNumber</span><span class="p">)</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># at this stage we know checkNumber appears only once, so we now update grid</span>
<span class="n">currentState</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGrid</span><span class="p">[</span><span class="n">item</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">individualNumber</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentState</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">individualNumber</span> <span class="o" style="color: #666666;">!=</span> <span class="n">checkNumber</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">individualNumber</span> <span class="o" style="color: #666666;">!=</span> <span class="s" style="color: #4070a0;">' '</span><span class="p">:</span>
<span class="n">currentState</span><span class="p">[</span><span class="n">individualNumber</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">' '</span>
<span class="n">currentGrid</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentState</span> </pre>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGrid</span></pre>
This is quite a large function, but don't panic! It is not complicated. As we run through the code it will become obvious what we are doing.<br />
<br />
First of all we need to go through each of the cells in our Sudoku one by one. This allows us to check the row associated with that cell and check if that cell has a number which is not in the rest of the row. We have done this a lot already.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;"># check all items in currentGrid list</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentGrid</span><span class="p">:</span></pre>
We will want to keep track of all the numbers in the row and all the numbers in the cell. So we create two lists to store this information.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;"># create two empty lists</span>
<span class="n">allNumbers</span> <span class="o" style="color: #666666;">=</span> <span class="p">[]</span>
<span class="n">currentNumbers</span> <span class="o" style="color: #666666;">=</span> <span class="p">[]</span>
</pre>
<div>
Now we look at all the cells in a row and store the any numbers, ignoring spaces, in the allNumbers list.</div>
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;"># determine all numbers remaining in the row - store in allNumbers</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">xRange</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">9</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">rowNumbers</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentGrid</span><span class="p">[(</span><span class="n">xRange</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">])]:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">rowNumbers</span> <span class="o" style="color: #666666;">!=</span> <span class="s" style="color: #4070a0;">' '</span><span class="p">:</span>
<span class="n">allNumbers</span><span class="o" style="color: #666666;">.</span><span class="n">append</span><span class="p">(</span><span class="n">rowNumbers</span><span class="p">)</span></pre>
We are using the xRange value to iterate through all cells in a row. The item[1] value is constant and determines the Y value.<br />
<br />
Now we do a similar thing, but we look at all the numbers in the individual cell we are currently in and store them in currentNumbers.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;"># determine numbers remaining in individual cell being looked at - store in currentNumbers</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">cellNumbers</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentGrid</span><span class="p">[</span><span class="n">item</span><span class="p">]:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">cellNumbers</span> <span class="o" style="color: #666666;">!=</span> <span class="s" style="color: #4070a0;">' '</span><span class="p">:</span>
<span class="n">currentNumbers</span><span class="o" style="color: #666666;">.</span><span class="n">append</span><span class="p">(</span><span class="n">cellNumbers</span><span class="p">)</span></pre>
If the cell has not been solved we will check the numbers from the cell, stored in cellNumbers against the numbers stored in the list allNumbers. We then check to to see if each number in the cell appears in the row only once.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="nb" style="color: #007020;">len</span><span class="p">(</span><span class="n">currentNumbers</span><span class="p">)</span> <span class="o" style="color: #666666;">></span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">checkNumber</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentNumbers</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">allNumbers</span><span class="o" style="color: #666666;">.</span><span class="n">count</span><span class="p">(</span><span class="n">checkNumber</span><span class="p">)</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span> </pre>
</pre>
If we find a number that only appears once we can say that that number is a solution for the cell we are currently in. We can update the grid to reflect this as follows.<br />
<br />
First we will take a list of the current remaining numbers in the cell and store it a list called currentState.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;"># at this stage we know checkNumber appears only once, so we now update grid</span>
<span class="n">currentState</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGrid</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> </pre>
We then iterate through each of the potential numbers in the current state.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">individualNumber</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentState</span><span class="p">:</span></pre>
Check each one to ensure it is not equal to the number we are trying to isolate in that cell, or equal to a space.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">individualNumber</span> <span class="o" style="color: #666666;">!=</span> <span class="n">checkNumber</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">individualNumber</span> <span class="o" style="color: #666666;">!=</span> <span class="s" style="color: #4070a0;">' '</span><span class="p">:</span> </pre>
We then turn these numbers into a space ' ' and update the dictionary in currentGrid to reflect this change.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">currentState</span><span class="p">[</span><span class="n">individualNumber</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">' '</span>
<span class="n">currentGrid</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentState</span> </pre>
Finally we return the currentGrid.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGrid</span></pre>
We can now create a function called onlyNinY, which is almost identical to the x function, but focusses on checking the column and not the row. Because it is so similar I wont go into this in any detail, but you should easily be able to spot the differences, and see how they relate to y and not x.<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">onlyNinY</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">):</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># check all items in currentGrid list</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentGrid</span><span class="p">:</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># create two empty lists</span>
<span class="n">allNumbers</span> <span class="o" style="color: #666666;">=</span> <span class="p">[]</span>
<span class="n">currentNumbers</span> <span class="o" style="color: #666666;">=</span> <span class="p">[]</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># determine all numbers remaining in the column - store in allNumbers</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">yRange</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">9</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">columnNumbers</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentGrid</span><span class="p">[(</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">],</span><span class="n">yRange</span><span class="p">)]:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">columnNumbers</span> <span class="o" style="color: #666666;">!=</span> <span class="s" style="color: #4070a0;">' '</span><span class="p">:</span>
<span class="n">allNumbers</span><span class="o" style="color: #666666;">.</span><span class="n">append</span><span class="p">(</span><span class="n">columnNumbers</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># determine numbers remaining in individual cell being looked at - store in currentNumbers</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">cellNumbers</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentGrid</span><span class="p">[</span><span class="n">item</span><span class="p">]:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">cellNumbers</span> <span class="o" style="color: #666666;">!=</span> <span class="s" style="color: #4070a0;">' '</span><span class="p">:</span>
<span class="n">currentNumbers</span><span class="o" style="color: #666666;">.</span><span class="n">append</span><span class="p">(</span><span class="n">cellNumbers</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># look at numbers remaining in a cell. Check if they only appear in the column once. </span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="nb" style="color: #007020;">len</span><span class="p">(</span><span class="n">currentNumbers</span><span class="p">)</span> <span class="o" style="color: #666666;">></span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">checkNumber</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentNumbers</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">allNumbers</span><span class="o" style="color: #666666;">.</span><span class="n">count</span><span class="p">(</span><span class="n">checkNumber</span><span class="p">)</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># at this stage we know checkNumber appears only once, so we now update grid</span>
<span class="n">currentState</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGrid</span><span class="p">[</span><span class="n">item</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">individualNumber</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentState</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">individualNumber</span> <span class="o" style="color: #666666;">!=</span> <span class="n">checkNumber</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">individualNumber</span> <span class="o" style="color: #666666;">!=</span> <span class="s" style="color: #4070a0;">' '</span><span class="p">:</span>
<span class="n">currentState</span><span class="p">[</span><span class="n">individualNumber</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">' '</span>
<span class="n">currentGrid</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentState</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGrid</span></pre>
<span class="n">Finally we need to look in the square relating to each cell. The function for this is also incredibly similar to the previous two functions, only we need to change our algorithm to check the grid and not rows or columns. Have a look at the function and you will see it is similar to the previous two with the exception that it determines the cells for the square in the same way we did in the removeGrid function in step 6. Therefore there is nothing new in this function we have not seen before. </span><br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">onlyNinGrid</span><span class="p">(</span><span class="n">currentGrid</span><span class="p">):</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># check all items in currentGrid list</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentGrid</span><span class="p">:</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># determine the co-ordinates for the grid we are dealing with</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;"><</span> <span class="mi" style="color: #40a070;">3</span><span class="p">:</span>
<span class="n">xGrid</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">></span> <span class="mi" style="color: #40a070;">5</span><span class="p">:</span>
<span class="n">xGrid</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">7</span><span class="p">,</span><span class="mi" style="color: #40a070;">8</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span> <span class="n">xGrid</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;"><</span> <span class="mi" style="color: #40a070;">3</span><span class="p">:</span>
<span class="n">yGrid</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">></span> <span class="mi" style="color: #40a070;">5</span><span class="p">:</span>
<span class="n">yGrid</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">7</span><span class="p">,</span><span class="mi" style="color: #40a070;">8</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span> <span class="n">yGrid</span> <span class="o" style="color: #666666;">=</span> <span class="p">[</span><span class="mi" style="color: #40a070;">3</span><span class="p">,</span><span class="mi" style="color: #40a070;">4</span><span class="p">,</span><span class="mi" style="color: #40a070;">5</span><span class="p">]</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># create two empty lists</span>
<span class="n">allNumbers</span> <span class="o" style="color: #666666;">=</span> <span class="p">[]</span>
<span class="n">currentNumbers</span> <span class="o" style="color: #666666;">=</span> <span class="p">[]</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#iterates through each of the nine numbers in the grid</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">xGrid</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">y</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">yGrid</span><span class="p">:</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># determine all numbers remaining in the grid - store in allNumbers</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">gridNumbers</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentGrid</span><span class="p">[(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">)]:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">gridNumbers</span> <span class="o" style="color: #666666;">!=</span> <span class="s" style="color: #4070a0;">' '</span><span class="p">:</span>
<span class="n">allNumbers</span><span class="o" style="color: #666666;">.</span><span class="n">append</span><span class="p">(</span><span class="n">gridNumbers</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># determine numbers remaining in individual cell being looked at - store in currentNumbers</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">cellNumbers</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentGrid</span><span class="p">[</span><span class="n">item</span><span class="p">]:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">cellNumbers</span> <span class="o" style="color: #666666;">!=</span> <span class="s" style="color: #4070a0;">' '</span><span class="p">:</span>
<span class="n">currentNumbers</span><span class="o" style="color: #666666;">.</span><span class="n">append</span><span class="p">(</span><span class="n">cellNumbers</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># look at numbers remaining in a cell. Check if they only appear in the grid once. </span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="nb" style="color: #007020;">len</span><span class="p">(</span><span class="n">currentNumbers</span><span class="p">)</span> <span class="o" style="color: #666666;">></span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">checkNumber</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentNumbers</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;">#</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">allNumbers</span><span class="o" style="color: #666666;">.</span><span class="n">count</span><span class="p">(</span><span class="n">checkNumber</span><span class="p">)</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># at this stage we know checkNumber appears only once, so we now update grid</span>
<span class="n">currentState</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentGrid</span><span class="p">[</span><span class="n">item</span><span class="p">]</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">individualNumber</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">currentState</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">individualNumber</span> <span class="o" style="color: #666666;">!=</span> <span class="n">checkNumber</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">individualNumber</span> <span class="o" style="color: #666666;">!=</span> <span class="s" style="color: #4070a0;">' '</span><span class="p">:</span>
<span class="n">currentState</span><span class="p">[</span><span class="n">individualNumber</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="s" style="color: #4070a0;">' '</span>
<span class="n">currentGrid</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">currentState</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">currentGrid</span></pre>
All that remains is a final F5 to save and run the program. As you click on the cells you will notice that if a number appears only once in the Row, column or square then that becomes resolved.<br />
<span class="n"><br /></span>
<span class="n"><a href="https://docs.google.com/file/d/0B87aGq7vEpoFLXhpT1FPNVNFZ1U/edit?usp=sharing" target="_blank">Sudoku Step 8 Source Code</a></span><br />
<span class="n"><br /></span><span class="n">Now the program is complete why not try seeing how it solves a few real Sudoku puzzles? While it will not solve all puzzles, it will solve some and will aid you solving the more difficult ones. There are loads of resources available on the internet about solving Sudoku. If you would like to look into programming more algorithms to improve your solver the internet is a good place to start.</span><br />
<span class="n"><br /></span>
<span class="n">I hope you have found this tutorial interesting and hopefully you have learnt a lot about programming in pygame along the way, I know I did while writing this blog. </span></div>
Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com15tag:blogger.com,1999:blog-8250429656532783188.post-21488178312054944552013-08-05T12:32:00.000+01:002013-08-05T21:00:03.905+01:00Python - Crossword SolverAs I have mentioned in a previous blog, one of the first programs I wrote in Python was a simple word checker. You type in a word and it checks to see if the word exists in a dictionary. Once I could program that I was able to expand the program into a crossword solver.<br />
<br />
One of the great things about programming is you can re-use code you have already written. Some of the code I wrote in my word checker program can be reused here. If you have not already done so, it might be worth you reading through my blog post covering the programming of the word checker, before progressing with this post.<br />
<br />
<a href="http://trevorappleton.blogspot.co.uk/2013/04/basic-python-programming-word-checker.html" target="_blank">Blog post of Word Checker.</a><br />
<br />
Again this program is quite small, but I think it demonstrates the power of Python, that you can achieve a lot in a few lines of code.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQ-PlTczJl16Kf8kUq_qg1I6uFM2_mDDOcUZ4TAQIs7cANJT7mr1STToAPWRPw_37mIycSTTdcygQzvS6ePKzAlj0YvZ99lZp9o1pRNq0FJmcBSkCvCdVyh0onPkdP-XZ2eBfG3J7vukc/s1600/546px-CrosswordUSA.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQ-PlTczJl16Kf8kUq_qg1I6uFM2_mDDOcUZ4TAQIs7cANJT7mr1STToAPWRPw_37mIycSTTdcygQzvS6ePKzAlj0YvZ99lZp9o1pRNq0FJmcBSkCvCdVyh0onPkdP-XZ2eBfG3J7vukc/s320/546px-CrosswordUSA.png" width="320" /></a></div>
<br />
<br />
The idea behind the Crossword Solver is you type a word with some letters missing, and the program works out all the possible words that would fit with the known letters and spaces.<br />
<br />
So for instance if you had an incomplete word in a crossword and you knew the first letter was 'f', you did not know the second or third letters, but knew the fourth was an 's' and the fifth was 't'. i.e. you are trying to find all words that would fit with 'f??st'<br />
<br />
The solution would be<br />
<br />
faust<br />
feast<br />
feist<br />
first<br />
foist<br />
frost<br />
<br />
There would be 6 words which fit.<br />
<br />
This blog is a tutorial teaching you how to create a program to solve this for you.<br />
<br />
Before programming this you will need access to a dictionary that your program can access. If you have not already done so, please download the file DictionaryE.txt from the link below. This is a text file which contains a lot of words.<br />
<br />
<a href="https://docs.google.com/file/d/0B87aGq7vEpoFd2FtakVINl90eEk/edit?usp=sharing" style="text-align: center;" target="_blank">Click here to download DictionaryE.txt</a><br />
<br />
Throughout this blog, where there could be confusion, I will show you what to type, and then show you a snippet of code showing the line you need to type and the preceding line. This should avoid any confusion about where you should be typing the code, and will show you the required level of indentation for each line.<br />
<br />
Ok let's get started!<br />
<br />
When writing a program I always roughly plan the program out first of all, and break it down into smaller sections. It always seems much less daunting when you think about each section individually, rather then the program as a whole. So for a crossword solver what do we need to be able to do?<br />
<br />
<br />
<ul>
<li>Stage 1. We need to somehow input our incomplete word to let the program know what we are trying to solve.</li>
<li>Stage 2. We also need to be able to access a list of real words in a dictionary.</li>
<li>Stage 3. We will then have to compare our incomplete word with the words in the dictionary and determine if they are a potential match.</li>
<li>Stage 4. Finally we will need to print any words which match the criteria.</li>
</ul>
<br />
<br />
Now we have planned our program, we can now start to program it.<br />
<br />
<h4>
Stage 1</h4>
<br />
Remember earlier I said that we can re-use code we have already written? Well in our word checker program we had the same requirement to input a word, and recall that word later. So let's use the same code here.<br />
<br />
In a new Python window type the following:<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">testWord</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">raw_input</span> <span class="p">(</span><span class="s" style="color: #4070a0;">'Please input a word to solve.</span><span class="se" style="color: #4070a0; font-weight: bold;">\n</span><span class="s" style="color: #4070a0;">Use Spaces to signify unkown letters: '</span><span class="p">)</span><span class="o" style="color: #666666;">.</span><span class="n">lower</span><span class="p">()</span></pre>
<br />
This stores our word into a variable called testWord.<br />
<br />
The \n tells the program to print the next text on a new line.<br />
<br />
The only difference between this line and the one in the word checker program is the fact I have changed the text explaining what input is required.<br />
<br />
<h4>
Stage 2</h4>
<br />
We need to be able to look at a list of real words. This is exactly the same as in the word checker program.<br />
<br />
Therefore you can copy the getDictionary() function into the top of your program.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">getDictionary</span><span class="p">():</span>
<span class="n">dictionaryOpen</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">open</span><span class="p">(</span><span class="s" style="color: #4070a0;">'dictionaryE.txt'</span><span class="p">,</span><span class="s" style="color: #4070a0;">'r'</span><span class="p">)</span>
<span class="n">dictionary</span> <span class="o" style="color: #666666;">=</span> <span class="n">dictionaryOpen</span><span class="o" style="color: #666666;">.</span><span class="n">read</span><span class="p">()</span><span class="o" style="color: #666666;">.</span><span class="n">split</span><span class="p">()</span>
<span class="n">dictionaryOpen</span><span class="o" style="color: #666666;">.</span><span class="n">close</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">dictionary</span></pre>
<br />
<br />
Ok that completed Stage 2. We have done half our program, and not had to type any new code. You should re-use code wherever possible, as it saves you so much time.<br />
<br />
<h4>
Stage 3</h4>
<br />
In this stage we need to compare our incomplete word with all the words in the dictionary.<br />
<br />
This is a little more tricky than the testWord function in the word checker program, so lets first think about how we will approach this.<br />
<br />
We now have a list of real words in the dictionary and an incomplete word. We want to find all the potential solutions.<br />
<br />
We can put together some rules which, if followed, would test a word from the dictionary and find potential match to our incomplete word.<br />
<br />
<u>Rule 1</u><br />
We know that for a word in the dictionary to be a potential match with our incomplete word, they need to be the same length. So we will only look at words the same length and rule out all those which are different lengths.<br />
<br />
<u>Rule 2</u><br />
As blanks are in effect wild cards and can be any letter we want to skip over any blanks in our incomplete word.<br />
<br />
<u>Rule 3</u><br />
For any letters in our incomplete word we want to see if it matches with the respective letter from each word in the dictionary. i.e. We want to make sure the first letter in our word matches the first letter of the word in the dictionary. We want to do the same for the second letter and the third letter and so on. We want to be able to know if all the non blank letters from our incomplete word match the respective letters for the word from the dictionary.<br />
<br />
So here are our three rules in summary.<br />
<br />
<ul>
<li>Check words are the same length.</li>
<li>Ignore any blanks.</li>
<li>Compare the 1st letter of the incomplete word with the 1st from the word in the dictionary. Then the second etc. Check they all match.</li>
</ul>
<br />
<br />
Are these three rules enough to solve the puzzle?<br />
<br />
Lets look at an example, and we will use the example of our incomplete word being<br />
<br />
<div style="text-align: center;">
'f st' </div>
<br />
with two blanks after the f.<br />
<br />
Lets compare this with the word apple using our rules above.<br />
<br />
They are both the same length, so rule 1 is satisfied.<br />
<br />
We can manually skip over each letter and compare letter 1 from 'f st' to 'apple'<br />
this would compare<br />
f --> a<br />
skip the next two letters as they are blanks (Rule 2)<br />
s --> l<br />
t --> e<br />
<br />
To satisfy Rule 3 all the non blank letters would have to match the respective letters in the word from the dictionary. In this case 0 out of the three non blanks matched. This is not a potential match.<br />
<br />
What about if we compared 'f st' to 'first'<br />
<br />
f --> f<br />
skip the next two letters as they are blanks. (Rule 2)<br />
s --> s<br />
t --> t<br />
<br />
We count those that match, which is 3 in this case, and compare this to the number of none blank letters which is 3. Therefore we can say this is a potential match.<br />
<br />
Im fairly confident that these three rules should satisfy what we need, so I will start to program a function to carry out this comparison.<br />
<br />
Let's start with creating our function. Underneath the getDictionary function type the following.<br />
<br />
def checkWord (testWord,dictionary):<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">checkWord</span> <span class="p">(</span><span class="n">testWord</span><span class="p">,</span><span class="n">dictionary</span><span class="p">):</span></pre>
<br />
We will call our function checkWord and will pass both our testWord variable, and the dictionary into this function so we can use both of these in a comparison.<br />
<br />
We know from our rules that in order to be a potential match all of the non blank letters have to match with the word from the dictionary. Therefore we will need to determine the number of non blank letters in our test word. This can be done before we look at any words in a dictionary, so lets look at this now.<br />
<br />
Before typing any more into our program, we shall look at two useful python commands we will use to work out the number of none blanks.<br />
<br />
The first is len()<br />
<br />
len(testWord)<br />
<br />
tells us how long testWord is.<br />
<br />
So that's the total length of the word including blanks.<br />
<br />
We can use a second command on testWord to count the number of blanks.<br />
<br />
This is:<br />
<br />
testWord.count(' ')<br />
<br />
So if there are two blanks, this will produce a number 2.<br />
<br />
So if we know how many letters are in the word, and how many are blanks, we can deduce the number which are not blanks.<br />
<br />
Therefore if we create a variable called nonBlanks, we should easily be able to work out the number of nonBlank characters in our word. Therefore type this equation into your function.<br />
<br />
nonBlanks = len(testWord)-testWord.count(' ')<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">checkWord</span> <span class="p">(</span><span class="n">testWord</span><span class="p">,</span><span class="n">dictionary</span><span class="p">):</span>
<span class="n">nonBlanks</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">len</span><span class="p">(</span><span class="n">testWord</span><span class="p">)</span><span class="o" style="color: #666666;">-</span><span class="n">testWord</span><span class="o" style="color: #666666;">.</span><span class="n">count</span><span class="p">(</span><span class="s" style="color: #4070a0;">' '</span><span class="p">)</span></pre>
<br />
<br />
For the rest of the function we need to check through each word in the dictionary and compare them to our incomplete word.<br />
<br />
To iterate through each word in our dictionary one at a time we can simply say:<br />
<br />
for word in dictionary:<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">nonBlanks</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">len</span><span class="p">(</span><span class="n">testWord</span><span class="p">)</span><span class="o" style="color: #666666;">-</span><span class="n">testWord</span><span class="o" style="color: #666666;">.</span><span class="n">count</span><span class="p">(</span><span class="s" style="color: #4070a0;">' '</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">word</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">dictionary</span><span class="p">:</span></pre>
<br />
Everything inside of this for loop will be carried out on each individual word.<br />
<br />
As we check each word there are a couple of things we should keep track of.<br />
<br />
<br />
<ul>
<li>We need to know which letter in both our word and the word from the dictionary we are comparing.</li>
<li>We want to be able to keep a count of any non blank letters which match.</li>
</ul>
<br />
<br />
So lets create two variables which we can increase as we do our counting.<br />
<br />
incLetter = 0<br />
incMatch = 0<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">word</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">dictionary</span><span class="p">:</span>
<span class="n">incLetter</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="n">incMatch</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span></pre>
<br />
incLetter will increase as we check each letter. This will keep track of what letter we are looking at.<br />
incMatch will increase as we match a letter.<br />
<br />
With these being inside the for loop they will reset to 0 each time a new word is checked. Just what we want.<br />
<br />
The next step is to start narrowing down potential options. The best way to do this is to discard any words which are not the same length as our potential word, which is Rule 1.<br />
<br />
We can use the len() function we used earlier to help with this.<br />
<br />
if len(word) == len(testWord):<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">incMatch</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="nb" style="color: #007020;">len</span> <span class="p">(</span><span class="n">word</span><span class="p">)</span> <span class="o" style="color: #666666;">==</span> <span class="nb" style="color: #007020;">len</span> <span class="p">(</span><span class="n">testWord</span><span class="p">):</span></pre>
<br />
So we will only progress further if the words match in length.<br />
<br />
now lets start another for loop to allow us to check each individual letter.<br />
<br />
for letter in testWord:<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="nb" style="color: #007020;">len</span> <span class="p">(</span><span class="n">word</span><span class="p">)</span> <span class="o" style="color: #666666;">==</span> <span class="nb" style="color: #007020;">len</span> <span class="p">(</span><span class="n">testWord</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">letter</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">testWord</span><span class="p">:</span></pre>
<br />
This will go through our testWord one letter at a time.<br />
<br />
There are three options now.<br />
<br />
<br />
<ul>
<li>If the letter is a blank, we want to ignore it, but we want to ensure we move onto the next letter in our word which covers Rule 2</li>
<li>If it is not a blank, we want to check this letter matches against the respective letter from the word in the dictionary. Increasing incMatch if the words match. We also want to then move onto the next letter in the word. This helps with Rule 3</li>
<li>If it doesnt match we just want to move onto the next letter. Again this helps with Rule 3.</li>
</ul>
<br />
<br />
The first part is to check if it is a blank and if so move onto the next letter.<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if letter == ' ':<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span> incLetter += 1<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">letter</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">testWord</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">letter</span> <span class="o" style="color: #666666;">==</span> <span class="s" style="color: #4070a0;">' '</span><span class="p">:</span>
<span class="n">incLetter</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span></pre>
<br />
So we say if the letter is equal to a blank, increase incLetter one.<br />
<br />
incLetter += 1 is a short way to say incLetter = incLetter + 1<br />
or increase incLetter by 1.<br />
<br />
The second option if the letter is not a blank should read<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>elif letter == word[incLetter]<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span> incLetter += 1<br />
incMatch += 1<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">incLetter</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">letter</span> <span class="o" style="color: #666666;">==</span> <span class="n">word</span><span class="p">[</span><span class="n">incLetter</span><span class="p">]:</span>
<span class="n">incLetter</span> <span class="o" style="color: #666666;">+=</span><span class="mi" style="color: #40a070;">1</span>
<span class="n">incMatch</span> <span class="o" style="color: #666666;">+=</span><span class="mi" style="color: #40a070;">1</span></pre>
<br />
What is word[incLetter] saying? Well why not try this in a Python shell? A great thing with Python is you can easily test things out in the shell as you go along. Click on Window and then Python Shell to load a shell window.<br />
<br />
Create a variable called word and store 'apple' in there.<br />
<br />
word = 'apple'<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlSrshYQRIbywFMKrVhTkstCLJTV8ncTse3eMNEqdbbtGXHR3z8PPa2PLt8L2-cP__HsISXVIbdGD4uqtT48KRp9rUtKsS8oag1qkVBDXCe968ksbp3RqG3-VBHgE44-tinRt9nCCeRFw/s1600/wordequalsapple.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="125" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlSrshYQRIbywFMKrVhTkstCLJTV8ncTse3eMNEqdbbtGXHR3z8PPa2PLt8L2-cP__HsISXVIbdGD4uqtT48KRp9rUtKsS8oag1qkVBDXCe968ksbp3RqG3-VBHgE44-tinRt9nCCeRFw/s320/wordequalsapple.PNG" width="320" /></a></div>
<br />
<br />
We can then find out what each individial letter in the word is by typing the following:<br />
<br />
word[0] returns 'a'<br />
word[1] returns 'p'<br />
word[2] returns 'p'<br />
word[3] returns 'l'<br />
word[4] returns 'e'<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhi_F2gru1IfdnPqEr2Dk9niwTkO5Hu8jeZUoJLfKwl1YQ87DJnilhccHd_iwTK54TJrln-8hPmsDKc1UGFjJLMfx9Bumsexzs8vcq13zE3MzFBfw-X9NoWSW5zCA1Ml-Lrl86icop3bxA/s1600/wordequalsappletest.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhi_F2gru1IfdnPqEr2Dk9niwTkO5Hu8jeZUoJLfKwl1YQ87DJnilhccHd_iwTK54TJrln-8hPmsDKc1UGFjJLMfx9Bumsexzs8vcq13zE3MzFBfw-X9NoWSW5zCA1Ml-Lrl86icop3bxA/s320/wordequalsappletest.PNG" width="286" /></a></div>
<br />
<br />
<br />
as incLetter = 0 we know we are looking at the first letter. If incLetter was 1 we would be looking at the second letter and so on. So its a way of moving through the word and keeing track of where we are up to.<br />
<br />
If the respective letters from both words match we will increase incLetter to move onto the next letter, and we will also increase incMatch to say the letters match.<br />
<br />
The third option is if the words are not a blank, and do not match. We dont want to do anything here other than move onto the next letter.<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>else:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span> incLetter += 1<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">incMatch</span> <span class="o" style="color: #666666;">+=</span><span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">incLetter</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span></pre>
<br />
How is that looking? Well to me it looks as though we are repeating ourselves several times. Every option we increase incLetter, and only do something different, increase incMatch, if the letters match.<br />
<br />
Lets rewrite that section from 'for letter in testWord:' to make it shorter.<br />
<br />
for letter in testWord:<br />
if letter == word[incLetter]:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>incMatch +=1<br />
incLetter += 1<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">letter</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">testWord</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">letter</span> <span class="o" style="color: #666666;">==</span> <span class="n">word</span><span class="p">[</span><span class="n">incLetter</span><span class="p">]:</span>
<span class="n">incMatch</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">incLetter</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span></pre>
</pre>
<br />
So this says if the letters match, increase incMatch but no matter what we need to increase incLetter so we start looking at the next letter.<br />
<br />
I think that has tidied up our program a little. Often when you see the code on the page it becomes obvious that things can be improved. Its not a bad thing. One thing I would say is make sure whatever you do you will understand it when you look at it in a few weeks, months or even years time. If you use a few extra lines, but it makes your code more readable, then leave the code longer.<br />
<br />
Now we have been through each letter in the word and compared them we need to report back if the word matches or not. This takes us onto the last stage.<br />
<br />
<h4>
Stage 4</h4>
<br />
We said at the beginning we would print any matching words onto the screen, so lets just do that.<br />
<br />
Our plan was that for words of the same length, if the number of matching letters equalled the number of non blank letters then we have a potential solution. As we have already determined if the words are the same length we can say.<br />
<br />
if incMatch == nonBlanks:<br />
print (word)<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">incLetter</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">incMatch</span> <span class="o" style="color: #666666;">==</span> <span class="n">nonBlanks</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="p">(</span><span class="n">word</span><span class="p">)</span></pre>
We will then move onto the next word in the dictionary. This is already taken care for us in the for loop.<br />
<br />
Once the loop has been through every word in the dictionary we shall exit out of the function with a simple return.<br />
<br />
return<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">print</span> <span class="p">(</span><span class="n">word</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span></pre>
<br />
So far we have done the following:<br />
<br />
<br />
<ul>
<li>We have asked the user to input an incomplete word they want to solve.</li>
<li>We have a function to create a dictionary.</li>
<li>We have a function which compares a word against each word in the dictionary and reports any potential solutions back.</li>
</ul>
<br />
<br />
All we need now is to tie the whole thing together.<br />
<br />
Underneath the user input lets get the dictionary and assign it to a variable we can pass into our function.<br />
<br />
dictionary = getDictionary()<br />
<br />
Finally we can run our testWord and the dictionary through the checkWord function.<br />
<br />
checkWord (testWord, dictionary)<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">dictionary</span> <span class="o" style="color: #666666;">=</span> <span class="n">getDictionary</span><span class="p">()</span>
<span class="n">checkWord</span> <span class="p">(</span><span class="n">testWord</span><span class="p">,</span><span class="n">dictionary</span><span class="p">)</span></pre>
<br />
Pressing F5 will now save and run your program.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvrezUqObJNQiy3U_v8VTS74IP8D6GTsDgcoRe5NOqXmsmGcCV3E_myhToCqcCKBRqz3FcFR31BWHiIGI-WrUJCyloApfgNq3MuA0REGi0-tzSl3QuJkv2l8fCE74CudJ_BLzZ8ekJgPY/s1600/crossword_start.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvrezUqObJNQiy3U_v8VTS74IP8D6GTsDgcoRe5NOqXmsmGcCV3E_myhToCqcCKBRqz3FcFR31BWHiIGI-WrUJCyloApfgNq3MuA0REGi0-tzSl3QuJkv2l8fCE74CudJ_BLzZ8ekJgPY/s1600/crossword_start.PNG" /></a></div>
<br />
Typing in 'f st' when asked should result in the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigXoWetynIrQKVul7LZx0A30-6CoEkVT0bWhmIQTehDnmGp5e4NcAh5L_VgnDjOPYd8cipg7Z2ePq74v6Fj1_Gqkh1D_FrCC7_UUx6WoMTrEjxIV6yKTMpMaD0jHw3LF4i4SFTo-MoZHk/s1600/crossword_end.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="128" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigXoWetynIrQKVul7LZx0A30-6CoEkVT0bWhmIQTehDnmGp5e4NcAh5L_VgnDjOPYd8cipg7Z2ePq74v6Fj1_Gqkh1D_FrCC7_UUx6WoMTrEjxIV6yKTMpMaD0jHw3LF4i4SFTo-MoZHk/s320/crossword_end.PNG" width="320" /></a></div>
<br />
If you would like the to download the source code you can from the following link.<br />
<br />
<a href="https://docs.google.com/file/d/0B87aGq7vEpoFdEl6ZWQtUzV4Vzg/edit?usp=sharing" target="_blank">Crossword Solver Source Code</a><br />
<br />
There we go, that should help you solve any crosswords. We have seen a few new concepts today, and it may seem a little daunting at first. The key is to break everything down into its most basic element.<br />
<br />
If you are struggling to understand, just read through the code one line at a time, and see if you can work out what it is doing.<br />
<div>
<br /></div>
Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com0tag:blogger.com,1999:blog-8250429656532783188.post-46426454994972242512013-07-29T12:26:00.000+01:002013-07-29T12:33:22.753+01:00Python - Game of Life - Alternative StartsIn an earlier blog post I explained how to write a version of Conway's Game of Life using Python and Pygame.<br />
<br />
<a href="http://trevorappleton.blogspot.co.uk/2013/07/python-game-of-life.html">Game of Life Blog</a><br />
<br />
The starting point for the 'game' was completely random. Before running the game we went through each of the cells in the grid and either made them alive or dead.<br />
<br />
As the Game of Life progresses the cells either multiply or die out depending upon the state of the surrounding cells. After a period of time the majority of the cells die, and eventually the system finishes in a stable state. You may well have a few oscillators, cells which live and die in a set pattern, but the system is stable.<br />
<br />
Does this have to be the case?<br />
<br />
People have spent a lot of time looking into the Game of Life and seeing if the system will ever become unstable. There are a few interesting starting patterns which I thought I would share, so you can use them as an alternative to the random pattern.<br />
<br />
If you remember, when programming the Game of Life we stored all the data about our cells in a dictionary called lifeDict. This dictionary listed the co-ordinates for each of the cells, and stored the information telling us if they were alive, using a 1, or dead, using a 0.<br />
<br />
To create this dictionary initially we called a function called blankGrid. This returned a dictionary containing all the cells. All the cells in this dictionary were dead.<br />
<br />
We then called a second function called startingGridRandom which set our starting grid to be completely random. To do this it randomly set all cells in the library as a 0, for dead, or a 1 for alive.<br />
<br />
If we wrote another function and used that to define our starting state layout instead of the startingGridRandom function we could play around with our starting state to try out a few different options. Let's do that now.<br />
<br />
I am assuming that you have already a working copy of my code for Conways Game of Life. If not you can download it from my previous blog by following this link.<br />
<br />
<a href="http://trevorappleton.blogspot.co.uk/2013/07/python-game-of-life.html">Game of Life Blog</a><br />
<br />
The first alternative starting state we will try is called the R-pentomino.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQQOh7SiSicE_sUBkhyphenhyphenmJwjFhEMnTVvAyIQxFe4wo6DdUT8KQplZUGOVYCgX7bPXvR_KGo1aADMdtLeYW5biqlEZPY2hAPWvLsTwFL0Yy8SO0Pn2TN9wFBydzmAyDOK_dD9wawTnvvUC8/s1600/Game_of_life_R-pertomino.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQQOh7SiSicE_sUBkhyphenhyphenmJwjFhEMnTVvAyIQxFe4wo6DdUT8KQplZUGOVYCgX7bPXvR_KGo1aADMdtLeYW5biqlEZPY2hAPWvLsTwFL0Yy8SO0Pn2TN9wFBydzmAyDOK_dD9wawTnvvUC8/s1600/Game_of_life_R-pertomino.png" /></a></div>
<br />
<br />
What I like about the R-pentomino is it releases gliders. A glider is a group of cells that appear to move across the screen. In other words they form a pattern that never stabilises, the pattern repeats until the glider runs off the screen.<br />
<br />
The R-pentomino grows quite large, so to avoid it hitting the side of the grid you will need to make a few modifications to the size of your grid.<br />
<br />
Set the global values of WINDOWWIDTH, WINDOWHEIGHT and CELLSIZE as shown below.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">640</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">450</span>
<span class="n">CELLSIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span></pre>
<br />
Now below the function called startingGridRandom we will create a new function called startingRPentomino. Again we will need the dictionary lifeDict to be passed to the function, so we can alter it to match our new starting point.<br />
<br />
As you can see from the image of the R-pentomino above there are 5 cells which we need to make alive to form the R-pentomino. I have experimented with this a lot, so know the cells produced (other than the gliders!) do not hit the edge of the grid. Each line below takes a co-ordinate on the grid and turns it into an alive cell. If you look at these co-ordinates you will see they form the R-pentomino. If you don't believe me, try plotting them onto some graph paper!<br />
<br />
Finally we need to return the cells which are in lifeDict<br />
<br />
The code for the new function should look like this.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">startingRpentomino</span><span class="p">(</span><span class="n">lifeDict</span><span class="p">):</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#R-pentomino</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">48</span><span class="p">,</span><span class="mi" style="color: #40a070;">32</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">49</span><span class="p">,</span><span class="mi" style="color: #40a070;">32</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">47</span><span class="p">,</span><span class="mi" style="color: #40a070;">33</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">48</span><span class="p">,</span><span class="mi" style="color: #40a070;">33</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">48</span><span class="p">,</span><span class="mi" style="color: #40a070;">34</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">lifeDict</span></pre>
<br />
Now in our main() function we can see that we make all cells blank and then we put the output from startingGridRandom() into lifeDict. Lets put a # in front of that line, which will stop our program calling it. Instead add a line underneath which calls our new starting function.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;">###Starting options</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#lifeDict = startingGridRandom(lifeDict) # Assign random life</span>
<span class="n">lifeDict</span> <span class="o" style="color: #666666;">=</span> <span class="n">startingRpentomino</span><span class="p">(</span><span class="n">lifeDict</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;"># Setup R-pentomino</span></pre>
<br />
Ok that should be all the changes we need in order to run the program. Press F5 to save and then run the program, and watch the R-pentimino do its thing.<br />
<br />
It's quite impressive that those few cells keep generating new cells for so long.<br />
<br />
Did you see the gliders moving across the screen?<br />
<br />
This looks good, but its not the most impressive. The R-pentomino is definitely trumped by the acorn. Although I am not sure, this must have gained its name because it grows as large as an oak! The acorn takes a whopping 5206 generation to stabilise, and releases a total of 13 gliders.<br />
<br />
A picture of the Acorn is shown below.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilyL48blR-Ty7U3g2LPpCCCJYkooptf3kW617Qg_qUY2cBTGdQAdnzb7SrwSi2S1pqAqohLXF7hgigHdRDL2b7U9qbh9PGoHi3Tqgp-943BsqZBVKwoT7EtHhFq2J7CVsV0DyE-qan2V0/s1600/Game_of_life_acorn.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilyL48blR-Ty7U3g2LPpCCCJYkooptf3kW617Qg_qUY2cBTGdQAdnzb7SrwSi2S1pqAqohLXF7hgigHdRDL2b7U9qbh9PGoHi3Tqgp-943BsqZBVKwoT7EtHhFq2J7CVsV0DyE-qan2V0/s1600/Game_of_life_acorn.png" /></a></div>
<br />
This grows larger than the grid system provided, but I will let you play around with the grid size you think you will need. Remember the larger the size of the grid the slower your program will run. For now leave it as it was for the R-pentomino.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">640</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">450</span>
<span class="n">CELLSIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span></pre>
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;">
</pre>
Write a new function underneath the startingRpentomino function called startingAcorn.<br />
<br />
To create the Acorn use the following co-ordinates.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">startingAcorn</span><span class="p">(</span><span class="n">lifeDict</span><span class="p">):</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Acorn</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">105</span><span class="p">,</span><span class="mi" style="color: #40a070;">55</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">106</span><span class="p">,</span><span class="mi" style="color: #40a070;">55</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">109</span><span class="p">,</span><span class="mi" style="color: #40a070;">55</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">110</span><span class="p">,</span><span class="mi" style="color: #40a070;">55</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">111</span><span class="p">,</span><span class="mi" style="color: #40a070;">55</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">106</span><span class="p">,</span><span class="mi" style="color: #40a070;">53</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">108</span><span class="p">,</span><span class="mi" style="color: #40a070;">54</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">lifeDict</span></pre>
<br />
Make sure you call the new startingAcorn function before pressing F5 to save and run the game.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;">###Starting options</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#lifeDict = startingGridRandom(lifeDict) # Assign random life</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#lifeDict = startingRpentomino(lifeDict) # Setup R-pentomino</span>
<span class="n">lifeDict</span> <span class="o" style="color: #666666;">=</span> <span class="n">startingAcorn</span><span class="p">(</span><span class="n">lifeDict</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;"># Setup Acorn</span></pre>
<br />
You should see this grows until it finally reaches a stable state.<br />
<br />
Another interesting starting position is called the die-hard. When this reaches a stable position there are no living cells left, they all die. It takes 130 generations for that to happen.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8Sg4UWKt4kC1CfW8miCXrionI7cuDYR9lfgzmtqFxXjtGRdhykgDKOY_iW72y3up_bFEh_dFNVvrvhYM2Il47TNwnGlUQbK4u0_34zFMTOowGc8Tec7iO-m4bHi-Ba44LWO6hkQEWDAY/s1600/Game_of_life_diehardpng.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8Sg4UWKt4kC1CfW8miCXrionI7cuDYR9lfgzmtqFxXjtGRdhykgDKOY_iW72y3up_bFEh_dFNVvrvhYM2Il47TNwnGlUQbK4u0_34zFMTOowGc8Tec7iO-m4bHi-Ba44LWO6hkQEWDAY/s1600/Game_of_life_diehardpng.png" /></a></div>
<br />
Set the size of the screen to the same as the R-pentoimino again.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">640</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">450</span>
<span class="n">CELLSIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span></pre>
<br />
The function to start off a Die-hard is as follows.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">startingDiehard</span><span class="p">(</span><span class="n">lifeDict</span><span class="p">):</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Diehard</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">45</span><span class="p">,</span><span class="mi" style="color: #40a070;">45</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">46</span><span class="p">,</span><span class="mi" style="color: #40a070;">45</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">46</span><span class="p">,</span><span class="mi" style="color: #40a070;">46</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">50</span><span class="p">,</span><span class="mi" style="color: #40a070;">46</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">51</span><span class="p">,</span><span class="mi" style="color: #40a070;">46</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">52</span><span class="p">,</span><span class="mi" style="color: #40a070;">46</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">51</span><span class="p">,</span><span class="mi" style="color: #40a070;">44</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">lifeDict</span></pre>
<br />
Make sure you place a # in front of the code calling the Acorn and write some new code to call the startingDiehard function.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;">###Starting options</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#lifeDict = startingGridRandom(lifeDict) # Assign random life</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#lifeDict = startingRpentomino(lifeDict) # Setup R-pentomino</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#lifeDict = startingAcorn(lifeDict) # Setup Acorn</span>
<span class="n">lifeDict</span> <span class="o" style="color: #666666;">=</span> <span class="n">startingDiehard</span><span class="p">(</span><span class="n">lifeDict</span><span class="p">)</span></pre>
<br />
Ok we have seen that a few cells can lead into a massive amount of growth before becoming stable, and it's possible for all cells to die before the stable position is reached. What if there was a pattern which created an unstable system? Well there are numerous, but the first one created was known as a Gosper Glider Gun. This was named after its creator - Bill Gosper. And unsurprisingly produces that cool pattern of unstable cells, which look as though they are moving across the screen... Gliders!<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmlvATI0ra1FA6hUSZ0FIOi0OTkTO_Z8md5V97pVpHQD1hBRmhzh1MYwDiM3K9ElIeb2S3oaj78jULuv_naI7vRjskMap27S3Wjpe2-xjPvG2sESXKS-a5D-KGL3_YIlm__rKbBBgm5BA/s1600/Game_of_life_glider_gun.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="93" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmlvATI0ra1FA6hUSZ0FIOi0OTkTO_Z8md5V97pVpHQD1hBRmhzh1MYwDiM3K9ElIeb2S3oaj78jULuv_naI7vRjskMap27S3Wjpe2-xjPvG2sESXKS-a5D-KGL3_YIlm__rKbBBgm5BA/s320/Game_of_life_glider_gun.png" width="320" /></a></div>
<br />
<br />
<br />
Keep the size of the screen as used previously.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">640</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">450</span>
<span class="n">CELLSIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">5</span></pre>
<br />
Below is the code which will create a Gosper Glider Gun<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">startingGosperGliderGun</span><span class="p">(</span><span class="n">lifeDict</span><span class="p">):</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Gosper Glider Gun</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#left square</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">15</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">5</span><span class="p">,</span><span class="mi" style="color: #40a070;">16</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">15</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">6</span><span class="p">,</span><span class="mi" style="color: #40a070;">16</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#left part of gun</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">15</span><span class="p">,</span><span class="mi" style="color: #40a070;">15</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">15</span><span class="p">,</span><span class="mi" style="color: #40a070;">16</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">15</span><span class="p">,</span><span class="mi" style="color: #40a070;">17</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">16</span><span class="p">,</span><span class="mi" style="color: #40a070;">14</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">16</span><span class="p">,</span><span class="mi" style="color: #40a070;">18</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">17</span><span class="p">,</span><span class="mi" style="color: #40a070;">13</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">18</span><span class="p">,</span><span class="mi" style="color: #40a070;">13</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">17</span><span class="p">,</span><span class="mi" style="color: #40a070;">19</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">18</span><span class="p">,</span><span class="mi" style="color: #40a070;">19</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">19</span><span class="p">,</span><span class="mi" style="color: #40a070;">16</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">20</span><span class="p">,</span><span class="mi" style="color: #40a070;">14</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">20</span><span class="p">,</span><span class="mi" style="color: #40a070;">18</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">21</span><span class="p">,</span><span class="mi" style="color: #40a070;">15</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">21</span><span class="p">,</span><span class="mi" style="color: #40a070;">16</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">21</span><span class="p">,</span><span class="mi" style="color: #40a070;">17</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">22</span><span class="p">,</span><span class="mi" style="color: #40a070;">16</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#right part of gun</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">25</span><span class="p">,</span><span class="mi" style="color: #40a070;">13</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">25</span><span class="p">,</span><span class="mi" style="color: #40a070;">14</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">25</span><span class="p">,</span><span class="mi" style="color: #40a070;">15</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">26</span><span class="p">,</span><span class="mi" style="color: #40a070;">13</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">26</span><span class="p">,</span><span class="mi" style="color: #40a070;">14</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">26</span><span class="p">,</span><span class="mi" style="color: #40a070;">15</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">27</span><span class="p">,</span><span class="mi" style="color: #40a070;">12</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">27</span><span class="p">,</span><span class="mi" style="color: #40a070;">16</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">29</span><span class="p">,</span><span class="mi" style="color: #40a070;">11</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">29</span><span class="p">,</span><span class="mi" style="color: #40a070;">12</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">29</span><span class="p">,</span><span class="mi" style="color: #40a070;">16</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">29</span><span class="p">,</span><span class="mi" style="color: #40a070;">17</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#right square</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">39</span><span class="p">,</span><span class="mi" style="color: #40a070;">13</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">39</span><span class="p">,</span><span class="mi" style="color: #40a070;">14</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">40</span><span class="p">,</span><span class="mi" style="color: #40a070;">13</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="mi" style="color: #40a070;">40</span><span class="p">,</span><span class="mi" style="color: #40a070;">14</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">lifeDict</span></pre>
<br />
Finally you need to call the startingGosperGliderGun function in the main part of your program to get this to work.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;">###Starting options</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#lifeDict = startingGridRandom(lifeDict) # Assign random life</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#lifeDict = startingRpentomino(lifeDict) # Setup R-pentomino</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#lifeDict = startingAcorn(lifeDict) # Setup Acorn</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#lifeDict = startingDiehard(lifeDict)</span>
<span class="n">lifeDict</span> <span class="o" style="color: #666666;">=</span> <span class="n">startingGosperGliderGun</span><span class="p">(</span><span class="n">lifeDict</span><span class="p">)</span></pre>
</pre>
<br />
I hope you have had fun playing around with different starting options for the game of life. This hopefully has given you a flavour of why people find the Game of Life so intriguing. Perhaps you can investigate some other starting options yourself which will beat those I have shown you here! <br />
<br />
<a href="https://docs.google.com/file/d/0B87aGq7vEpoFaG1RbDJEYThuVmM/edit?usp=sharing">Source Code Game of Life - Alternative Starts</a>Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com1tag:blogger.com,1999:blog-8250429656532783188.post-5346031456723923422013-07-22T21:52:00.001+01:002013-09-25T09:32:34.208+01:00Python - Game of LifeWhile looking through a few programming forums I kept noticing people with a slightly odd looking avatar.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-mpspBf5tijDoxTZNClJRid1KHkgmVge8XQyHdLlWmuUPLcLi0EdPx5TITrWJYIbJLbnAeHUISraYpoyYmkcpQoHm-9PJ7peyg13aP1zx8Nk-p3R9nD2-hVNVG8cr_Ub0e0BeYRodCis/s1600/glider.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-mpspBf5tijDoxTZNClJRid1KHkgmVge8XQyHdLlWmuUPLcLi0EdPx5TITrWJYIbJLbnAeHUISraYpoyYmkcpQoHm-9PJ7peyg13aP1zx8Nk-p3R9nD2-hVNVG8cr_Ub0e0BeYRodCis/s1600/glider.png" /></a></div>
<pre style="background-color: white; color: #333333;"></pre>
<br />
I thought that for the same emblem to keep cropping up it must have some meaning, but I had no idea what that was.<br />
<br />
It took a few attempts at googling to find the symbols meaning. Trying to describe a symbol to google is not easy! I found that the symbol was derived from Conway's Game of Life. The symbol represents a Glider which is sometimes created during the Game of Life. The reason people use it as an avatar is because the symbol has been adopted by the hacking community in a similar way that Linux has Tux as its emblem.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV9ZB5pAg5H8KIVVh-zHP6BoSgS4FRQqpIQKudlDdiHMUGDoZDfJOkQMa1in84ek5asL_LjxgjCUHj4sR4Csi90yahdzP-bAk0aElVT-VvlNMDttEH3XlbmELVj4yFi2hMQDYw78QRokE/s1600/220px-Tux.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV9ZB5pAg5H8KIVVh-zHP6BoSgS4FRQqpIQKudlDdiHMUGDoZDfJOkQMa1in84ek5asL_LjxgjCUHj4sR4Csi90yahdzP-bAk0aElVT-VvlNMDttEH3XlbmELVj4yFi2hMQDYw78QRokE/s1600/220px-Tux.png" /></a></div>
<br />
<br />
Reading about the <a href="http://en.wikipedia.org/wiki/Conway's_Game_of_Life">Game of Life on Wikipedia</a> I became quite interested in the concept.<br />
<br />
The Game of Life is in short a simulation of a group of cells. At every step in time, often referred to in the game as a tick, cells live or die depending on their surroundings.<br />
<br />
There are four rules which are applied simultaneously to all the cells in the game.<br />
<br />
1. Any live cell with fewer than two live neighbours dies, as if caused by under-population.<br />
2. Any live cell with two or three live neighbours lives on to the next generation.<br />
3. Any live cell with more than three live neighbours dies, as if by overcrowding.<br />
4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.<br />
<br />
However I made my mind up that it must be too difficult to program, so I filed it away as one of those things to try when I am a better programmer.<br />
<br />
For various reasons I was drawn towards giving pygame a whirl. I had played around with it in the past and felt it might potentially offer a nicer way to display certain things than Tkinter, which is my default for any GUI work in Python. I felt there was some potential there other than for writing games.<br />
<br />
I learnt to program in Python using the free book 'Invent Your Own Computer Games with Python' by Al Sweigart. I cannot rate this book highly enough. If you want to learn Python, use this book. It is that good.<br />
<br />
I knew he had also written a book aimed at teaching the basics of pygame. After my great experience with his first book, I thought I could not go wrong with his book called 'Making Games with Python and Pygame'. (These two books plus his latest book 'Hacking Secret Ciphers with Python' can be found on the website <a href="http://inventwithpython.com/">http://inventwithpython.com/</a>)<br />
<br />
I skimmed through the first few chapters of this book and knowing I learn better by doing, I thought I would crack on and write my own game. But what? Having seen that the first of the games in the pygame book revolved around a grid system, I thought I could always try and write a version of the Game of Life. I still had a feeling it would be too difficult, but I was up for the challenge.<br />
<br />
After starting and finishing the program much quicker than anticipated, and once again astounding myself with how easy things are to do in Python, I thought it would make a great blog post. <br />
<br />
Pygame comes as standard on the Raspberry Pi however if you are using a different platform for programming then you can download it from here:<br />
<br />
<a href="http://www.pygame.org/news.html">http://www.pygame.org/news.html</a><br />
<br />
This tutorial will lead you through my thought process for developing and creating this game. There will be a link to the code at the end for those who want to download it. :-)<br />
<br />
I am going to assume you know how to start programming in Python. If not I have a previous blog which should get you up to speed.<br />
<br />
<a href="http://trevorappleton.blogspot.co.uk/2013/04/basic-python-programming-word-checker.html">http://trevorappleton.blogspot.co.uk/2013/04/basic-python-programming-word-checker.html</a><br />
<br />
I am not going to go into all the details of how pygame works. Al Sweigart does a much better job of this that I ever could and having only started with pygame recently, I feel I would only be copying his good work. His book is definitely worth reading.<br />
<br />
Throughout this blog I will show you what to type, and then show you a snippet of code showing the line you need to type and some preceding lines. This should avoid any confusion about where you should be typing the code, and will show you the required level of indentation for each line.<br />
<br />
I am going to run through the process of producing the Game of Life in 4 stages.<br />
<br />
Stage 1 - Creating a blank pygame screen.<br />
Stage 2 - Creating a blank grid on the pygame screen.<br />
Stage 3 - Creating random coloured cells on the screen.<br />
Stage 4 - Working Game of Life.<br />
<br />
A link to the source code is available at the end of each stage.<br />
<br />
<h4>
Stage 1 - Creating a blank pygame screen. </h4>
<div>
<br /></div>
The first thing I needed to achieve was to get a blank screen up and running. Luckily Al Sweigart provided the code to do this, so I did not have to go re-inventing the wheel.<br />
<br />
Type in the following and then press F5 to save and run the code.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"><span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">pygame</span><span class="o" style="color: #666666;">,</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">sys</span>
<span class="kn" style="color: #007020; font-weight: bold;">from</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">pygame.locals</span> <span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">init</span><span class="p">()</span>
<span class="n">DISPLAYSURF</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_mode</span><span class="p">((</span><span class="mi" style="color: #40a070;">400</span><span class="p">,</span><span class="mi" style="color: #40a070;">300</span><span class="p">))</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_caption</span><span class="p">(</span><span class="s" style="color: #4070a0;">'Hello World'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">while</span> <span class="bp" style="color: #007020;">True</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;">#main game loop</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">event</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">QUIT</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">quit</span><span class="p">()</span>
<span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span></pre>
</pre>
There are three main points to know about this code.<br />
<br />
1. DISPLAYSURF = pygame.display.set_mode((400,300))<br />
This sets the size of the window. Run the code with different numbers and see what happens. Don't forget these numbers are within two sets of brackets!<br />
<br />
2. pygame.display.set_caption('Hello World')<br />
This sets the title of the Window. Change 'Hello World' to 'Game of Life' and see what happens.<br />
<br />
3. while True: #main game loop<br />
As the comment suggests this is the main game loop. Everything that needs repeating within our game will need to be contained within this loop.<br />
<br />
Now press F5 to save and run your program. Is this what you see?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEn77XKSdJ5XSmGi1_5gR78fMfKNWaAkvmpO697vODlPkO60GZps-pOIAipArVLJhuAo_G-_0NKmgDur7d3KyhCtyXWqECuymZaoZfun1UlnH1L10A5yvwWJKeLvIK3Lb2ppHg51OTABA/s1600/GoL_Blank.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="264" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEn77XKSdJ5XSmGi1_5gR78fMfKNWaAkvmpO697vODlPkO60GZps-pOIAipArVLJhuAo_G-_0NKmgDur7d3KyhCtyXWqECuymZaoZfun1UlnH1L10A5yvwWJKeLvIK3Lb2ppHg51OTABA/s320/GoL_Blank.PNG" width="320" /></a></div>
<br />
<br />
That was fairly simple wasn't it? Ok it doesn't do much but it gives us great foundations for building upon.<br />
<br />
<a href="https://docs.google.com/file/d/0B87aGq7vEpoFRWhvZ1k1RjdyYXc/edit?usp=sharing" target="_blank">Blank Screen Source Code</a><br />
<br />
<h4>
Stage 2 - Creating a blank grid on the pygame screen</h4>
<br />
My next step was to see how to create and display a grid on the screen.<br />
<br />
The first thing I did was to create global variables for the width and height of the window. I thought I may like to increase or decrease the size of the window during testing and running the Game of Life.<br />
<br />
WINDOWWIDTH = 640<br />
WINDOWHEIGHT = 480<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">pygame</span><span class="o" style="color: #666666;">,</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">sys</span>
<span class="kn" style="color: #007020; font-weight: bold;">from</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">pygame.locals</span> <span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">640</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">480</span></pre>
<br />
<br />
We will now have to change the window size so it uses the values from WINDOWWIDTH and WINDOWHEIGHT rather than the values we had previously typed in there.<br />
<br />
Therefore change the line:<br />
<br />
DISPLAYSURF = pygame.display.set_mode((400,300))<br />
<br />
to<br />
<br />
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH,WINDOWHEIGHT))<br />
<div>
<br /></div>
<br />
Having these as global variables means you can change the values at one location in your code, and not all the way through.<br />
<br />
I also wanted to ensure I could change the size of the cells. Again this allowed me to have larger or smaller populations within the window so I created another global variable.<br />
<br />
CELLSIZE = 10<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"><span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">640</span>
<span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">480</span>
<span class="n">CELLSIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">10</span></pre>
</pre>
<br />
The next two lines make use of the assert command.<br />
<br />
assert WINDOWWIDTH % CELLSIZE == 0, "Window width must be a multiple of cell size"<br />
assert WINDOWHEIGHT % CELLSIZE == 0, "Window height must be a multiple of cell size"<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">CELLSIZE</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">10</span>
<span class="k" style="color: #007020; font-weight: bold;">assert</span> <span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">%</span> <span class="n">CELLSIZE</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="s" style="color: #4070a0;">"Window width must be a multiple of cell size"</span>
<span class="k" style="color: #007020; font-weight: bold;">assert</span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">%</span> <span class="n">CELLSIZE</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="s" style="color: #4070a0;">"Window height must be a multiple of cell size"</span></pre>
<br />
<br />
The idea behind using the assert command is to catch any bugs you may have as early as possible. The assert command carries out a calculation in a controlled location, and if it fails will let you know. It is easier to catch a bug if you go looking for it rather than it surprising you later on. We are using the assert command to check if there are an exact number of cell sizes within the width and height of the window.<br />
<br />
How do we check if there is an exact number of cells able to fit into the window we have specified? We need to be able to check if the the size of the window divided by the size of the cells gives us an exact number. To do this we can use the mod (%) function. This divides two numbers and reports back the remainders.<br />
<br />
An example should explain it.<br />
<br />
We know how dividing works.<br />
<br />
15 / 4 = 3.75<br />
<br />
The mod function on the other hand reports back any remainders.<br />
<br />
15 % 4 = 3<br />
<br />
Shall we just look into that last equation again? 4 goes into 15 three whole times (3 x 4 = 12) with a remainder of 3.<br />
<br />
20 % 3 = 2<br />
<br />
Three goes into 20 six times (3 x 6 = 18) therefore the remainder is 2.<br />
<br />
If one number goes into another number an exact number of times, then the mod would be 0.<br />
<br />
Hopefully that all makes sense!<br />
<br />
The next two lines determine how many cells there are in the x direction (CELLWIDTH) and in the y direction (CELLHEIGHT). This will be useful to us later on.<br />
<br />
CELLWIDTH = WINDOWWIDTH / CELLSIZE # number of cells wide<br />
CELLHEIGHT = WINDOWHEIGHT / CELLSIZE # Number of cells high<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">assert</span> <span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">%</span> <span class="n">CELLSIZE</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="s" style="color: #4070a0;">"Window width must be a multiple of cell size"</span>
<span class="k" style="color: #007020; font-weight: bold;">assert</span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">%</span> <span class="n">CELLSIZE</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="s" style="color: #4070a0;">"Window height must be a multiple of cell size"</span>
<span class="n">CELLWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">/</span> <span class="n">CELLSIZE</span> <span class="c" style="color: #60a0b0; font-style: italic;"># number of cells wide</span>
<span class="n">CELLHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">/</span> <span class="n">CELLSIZE</span> <span class="c" style="color: #60a0b0; font-style: italic;"># Number of cells high</span></pre>
<div>
<br />
<br /></div>
The last global variables we will specify for now define some colours. Lets define a black, a white and a dark gray for now. These colours are defined using RGB, the amount of Red, Green and Blue in the mix to make up the colour.<br />
<br />
# set up the colours<br />
BLACK = (0, 0, 0)<br />
WHITE = (255,255,255)<br />
DARKGRAY = (40, 40, 40)<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"><span class="n">CELLWIDTH</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWWIDTH</span> <span class="o" style="color: #666666;">/</span> <span class="n">CELLSIZE</span> <span class="c" style="color: #60a0b0; font-style: italic;"># number of cells wide</span>
<span class="n">CELLHEIGHT</span> <span class="o" style="color: #666666;">=</span> <span class="n">WINDOWHEIGHT</span> <span class="o" style="color: #666666;">/</span> <span class="n">CELLSIZE</span> <span class="c" style="color: #60a0b0; font-style: italic;"># Number of cells high</span>
<span class="c" style="color: #60a0b0; font-style: italic;"># set up the colours</span>
<span class="n">BLACK</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="mi" style="color: #40a070;">0</span><span class="p">)</span>
<span class="n">WHITE</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">)</span>
<span class="n">DARKGRAY</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">40</span><span class="p">,</span> <span class="mi" style="color: #40a070;">40</span><span class="p">,</span> <span class="mi" style="color: #40a070;">40</span><span class="p">)</span></pre>
</pre>
<br />
Lets go and write the main part of the software now. We will modify the code we wrote during stage one to create the blank screen. After typing def main(): indent the remainder of the blank screen code as shown to place the code within the main function.<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">main</span><span class="p">():</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">init</span><span class="p">()</span>
<span class="n">DISPLAYSURF</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_mode</span><span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_caption</span><span class="p">(</span><span class="s" style="color: #4070a0;">'Game of Life'</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">while</span> <span class="bp" style="color: #007020;">True</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;">#main game loop</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">event</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">QUIT</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">quit</span><span class="p">()</span>
<span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span></pre>
</pre>
<br />
We will have to add global DISPLAYSURF into the main function, so add this below the pygame.init() line.<br />
<br />
global DISPLAYSURF<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"></pre>
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">init</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">global</span> <span class="n">DISPLAYSURF</span>
<span class="n">DISPLAYSURF</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_mode</span><span class="p">((</span><span class="n">WINDOWWIDTH</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span></pre>
<br />
<br />
Lets now make the background of the screen white in colour.<br />
<br />
DISPLAYSURF.fill(WHITE)<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">set_caption</span><span class="p">(</span><span class="s" style="color: #4070a0;">'Game of Life'</span><span class="p">)</span>
<span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">(</span><span class="n">WHITE</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;">#fills the screen white</span></pre>
<br />
<br />
Before we get into the main loop, lets draw our grid. We will write the function later to draw this, so lets just call that function for now.<br />
<br />
drawGrid()<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">(</span><span class="n">WHITE</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;">#fills the screen white</span>
<span class="n">drawGrid</span><span class="p">()</span></pre>
<br />
<br />
Then we shall update the display to show the new grid.<br />
<br />
pygame.display.update()<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">drawGrid</span><span class="p">()</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span></pre>
<br />
<br />
I have drawn the grid and updated the screen before the main game loop, so the screen is set up before we get into the main part of the game. However we will want to do the same thing for each generation, or tick, as it is known in the Game of Life. So lets also add drawGrid() into the while loop.<br />
<br />
drawGrid()<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span>
<span class="n">drawGrid</span><span class="p">()</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span></pre>
<br />
<br />
Now after the main function we have just written, lets write some code to call main function, otherwise the Game of Life will never start.<br />
<br />
if __name__=='__main__':<br />
main()<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; overflow: auto; padding: 10px;"> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">__name__</span><span class="o" style="color: #666666;">==</span><span class="s" style="color: #4070a0;">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span></pre>
</pre>
<br />
All that is left is for us to write that function we called earlier to draw the grid! We will write this function directly after where we set the global variables for colours.<br />
<br />
As always, the first thing we will do is to define the function name.<br />
<br />
def drawGrid():<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">DARKGRAY</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">40</span><span class="p">,</span> <span class="mi" style="color: #40a070;">40</span><span class="p">,</span> <span class="mi" style="color: #40a070;">40</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Draws the grid lines</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">drawGrid</span><span class="p">():</span></pre>
<br />
<br />
Now we need to draw lines to map out each of the different cells. We have put some work in upfront which tells us the size of the window, the cell size and the number of cells. We know from our assert functions there are the correct number of cells for the size of the screen, so we can concentrate on drawing the grid.<br />
<br />
We will want to draw vertical lines across the width of the screen separated by the width of the size of each cell.<br />
<br />
How will we do this?<br />
<br />
Well if you type the following into the IDLE command line:<br />
<br />
for x in range (100):<br />
print x<br />
<br />
We see the numbers from 1 - 100<br />
<br />
Now try:<br />
<br />
for x in range (20,30):<br />
<span style="white-space: pre;"> </span>print x<br />
<br />
We see the numbers 20 to 29 inclusive.<br />
<br />
Now try:<br />
<br />
for x in range (20,30,2):<br />
<span style="white-space: pre;"> </span>print x<br />
<br />
We see the numbers 20,22,24,26,28<br />
<br />
So the 20 defines the starting number, the 30 the finishing number, and the 2 the size of the step we should take.<br />
<br />
We know the start of our window will be 0, we know the end will be WINDOWWIDTH and we know the spacing we should use is CELLSIZE. So we can use the range command to determine where we should draw our grid lines.<br />
<br />
for x in range(0, WINDOWWIDTH, CELLSIZE): # draw vertical lines<br />
<br />
we can then use a pygame function to draw out grid lines at each value of x<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>pygame.draw.line(DISPLAYSURF, DARKGRAY, (x,0),(x,WINDOWHEIGHT))<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">drawGrid</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="n">WINDOWWIDTH</span><span class="p">,</span> <span class="n">CELLSIZE</span><span class="p">):</span> <span class="c" style="color: #60a0b0; font-style: italic;"># draw vertical lines</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">DARKGRAY</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">),(</span><span class="n">x</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span></pre>
<br />
<br />
Lets just look at the code within this line.<br />
<br />
DISPLAYSURF is required to draw the line.<br />
DARKGRAY uses our global variable to set the colour of the line.<br />
The (x,0) are the co-ordinates mapping out the start of the line. We want it to start at the top of the screen which is y = 0. Remember x will increase by a CELLWIDTH amount each time.<br />
(x,WINDOWHEIGHT) sets the end co-ordinate. We want it to finish at the bottom of the screen, which is the height of the window, which we defined as a global variable WINDOWHEIGHT earlier in our program. Again x will increase as we go through the range of values.<br />
<br />
Lets run our program and see how it looks.<br />
<br />
Do you get a white screen with vertical gray lines on it? Perfect.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi71nV2BomZWvCNduJPtrJ8Rk0zE_PBuPl1Z9LT32fwYtomMB1R9hxuVhGyyBwazFwoLtYzPi0ZKbxt4ynf80oEX2E1Up5ShP_QgR3vIKh9AG6PI5xIobpQedlsr75x-RYUsxC8cCXd184/s1600/GoL_VertivalLines.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="262" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi71nV2BomZWvCNduJPtrJ8Rk0zE_PBuPl1Z9LT32fwYtomMB1R9hxuVhGyyBwazFwoLtYzPi0ZKbxt4ynf80oEX2E1Up5ShP_QgR3vIKh9AG6PI5xIobpQedlsr75x-RYUsxC8cCXd184/s320/GoL_VertivalLines.PNG" width="320" /></a></div>
<br />
<br />
Lets add some code to the drawGrid function for the horizontal lines.<br />
<br />
for y in range (0, WINDOWHEIGHT, CELLSIZE): # draw horizontal lines<br />
<br />
The range is the almost the same but we want to use WINDOWHEIGHT to determine the max value in the range.<br />
<br />
Similarly for the draw.line function<br />
<br />
pygame.draw.line(DISPLAYSURF, DARKGRAY, (0,y), (WINDOWWIDTH, y))<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;">#Draws the grid lines</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">drawGrid</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="n">WINDOWWIDTH</span><span class="p">,</span> <span class="n">CELLSIZE</span><span class="p">):</span> <span class="c" style="color: #60a0b0; font-style: italic;"># draw vertical lines</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">DARKGRAY</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">),(</span><span class="n">x</span><span class="p">,</span><span class="n">WINDOWHEIGHT</span><span class="p">))</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">y</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="n">WINDOWHEIGHT</span><span class="p">,</span> <span class="n">CELLSIZE</span><span class="p">):</span> <span class="c" style="color: #60a0b0; font-style: italic;"># draw horizontal lines</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">DARKGRAY</span><span class="p">,</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="n">y</span><span class="p">),</span> <span class="p">(</span><span class="n">WINDOWWIDTH</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span></pre>
<br />
<br />
Now we say that the y value should change each iteration through the range, and the x values of 0 and WINDOWWIDTH should stay constant.<br />
<br />
Once again run your program. Does your screen now look like this? Perfect!<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPirYQBN7ojtLQHIgX1V605MNyNNg-zzPRvrsP0OwGtFeH4ekwURZrKf3mFg7bLyMYUyjLSj4rUPx_UVdq6Ve4-uM7eBuum9mSzUWbqLFi1L6bkxp-SNBS3oFzbt4pJW1MTVqXgONiOFA/s1600/GoL_BlankGrid.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="261" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPirYQBN7ojtLQHIgX1V605MNyNNg-zzPRvrsP0OwGtFeH4ekwURZrKf3mFg7bLyMYUyjLSj4rUPx_UVdq6Ve4-uM7eBuum9mSzUWbqLFi1L6bkxp-SNBS3oFzbt4pJW1MTVqXgONiOFA/s320/GoL_BlankGrid.PNG" width="320" /></a></div>
<br />
<br />
We have finished creating the basis of the Game of Life board.<br />
<br />
<a href="https://docs.google.com/file/d/0B87aGq7vEpoFejZVemRlUXBuNkE/edit?usp=sharing" target="_blank">Blank Grid Source Code</a><br />
<br />
<h4>
Stage 3 - Creating random coloured cells on the screen</h4>
<div>
<br /></div>
Lets now try to fill some of the cells with life, and colour those that are alive a different colour. To begin with we will randomly assign life to some of the cells.<br />
<br />
First we need a strategy for checking which cells are alive and which cells are dead. We can use a dictionary to keep track of the cells and if they are dead, we can label them with a 0, or if they are alive we can use a 1.<br />
<br />
Let us create a function to create a dictionary of all the cells and to start with lets assign them all a 0. We can easily change the 0 to a 1 later on.<br />
<br />
Below the drawGrid() function let us create a new function called blankGrid.<br />
<br />
def blankGrid():<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">line</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">DARKGRAY</span><span class="p">,</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="n">y</span><span class="p">),</span> <span class="p">(</span><span class="n">WINDOWWIDTH</span><span class="p">,</span> <span class="n">y</span><span class="p">))</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">blankGrid</span><span class="p">():</span></pre>
<br />
<br />
We have said we will store the information about the cell location, if it is dead or alive, in a dictionary.<br />
<br />
Earlier in our program we stored global variables to keep track of the number of cells in the x direction (CELLWIDTH) and those in the y direction (CELLHEIGHT)<br />
<br />
We can use the position of the cell in x and y as co-ordinates to give each one a unique number. That way we can easily know which cell we are talking about.<br />
<br />
To do this we need two for loops. One dealing with x and the other with y.<br />
<br />
Lets type the code and then analyse it<br />
<br />
gridDict = {}<br />
for y in range (CELLHEIGHT):<br />
for x in range (CELLWIDTH):<br />
gridDict[x,y] = 0<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">blankGrid</span><span class="p">():</span>
<span class="n">gridDict</span> <span class="o" style="color: #666666;">=</span> <span class="p">{}</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">y</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span> <span class="p">(</span><span class="n">CELLHEIGHT</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span> <span class="p">(</span><span class="n">CELLWIDTH</span><span class="p">):</span>
<span class="n">gridDict</span><span class="p">[</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
</pre>
<br />
<br />
First we are creating a new dictionary, to allow us to store the data we are about to create. This is called gridDict.<br />
<br />
Now we see two for loops, the second one indented in the first one.<br />
<br />
The y loop says iterate through all the integers (whole numbers) in CELLHEIGHT. This will start at 0, then 1, then 2 all the way up to the number that is stored in CELLHEIGHT. However before moving from one number to the second number, we run through the second for loop. This deals with all the numbers in CELLWIDTH.<br />
<br />
These co-ordinates are stored in our new dictionary and assigned the number 0.<br />
<br />
So if CELLHEIGHT is 3 and CELLWIDTH is 2 we would see<br />
<br />
y = 0 and x = 0 placed into the dictionary<br />
y = 0 and x = 1 placed into the dictionary<br />
y = 0 and x = 2 placed into the dictionary<br />
<br />
As we have moved through all the values in x, the value of y increases<br />
<br />
y = 1 and x = 0 placed into the dictionary<br />
y = 1 and x = 1 placed into the dictionary<br />
y = 1 and x = 2 placed into the dictionary<br />
<br />
again y would increase<br />
<br />
y = 2 and x = 0 placed into the dictionary<br />
y = 2 and x = 1 placed into the dictionary<br />
y = 2 and x = 2 placed into the dictionary<br />
<br />
and so on until all the numbers have been used.<br />
<br />
This technique is used a lot in programming so it is worth you spending a few minutes thinking about what is happening here if you are unsure.<br />
<br />
Once we have been through all our cells and stored them with a 0 in the dictionary, we can return the dictionary.<br />
<br />
return gridDict<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">gridDict</span><span class="p">[</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">gridDict</span></pre>
<br />
<br />
Now we call this function in the main part of our program. Underneath DISPLAYSURF.fill(WHITE) place the result from the function blankGrid into lifeDict<br />
<br />
lifeDict = blankGrid()<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">DISPLAYSURF</span><span class="o" style="color: #666666;">.</span><span class="n">fill</span><span class="p">(</span><span class="n">WHITE</span><span class="p">)</span>
<span class="n">lifeDict</span> <span class="o" style="color: #666666;">=</span> <span class="n">blankGrid</span><span class="p">()</span> <span class="c" style="color: #60a0b0; font-style: italic;"># creates library and populates to match blank grid</span></pre>
<br />
<br />
Ok when we started this section we said we would assign random life to each cell. So far we have assigned a 0. We could have instead assigned a random number in the blankGrid function, but that would have limited our options for playing around with the Game of Life code later. So lets now call a second function to assign a 0 or 1 to our cells.<br />
<br />
Lets call the function startingGridRandom<br />
<br />
We want to modify our dictionary so we know which items are alive or dead. Therefore lets pass the dictionary into the funtion so we can modify it.<br />
<br />
lifeDict = startingGridRandom(lifeDict)<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">lifeDict</span> <span class="o" style="color: #666666;">=</span> <span class="n">blankGrid</span><span class="p">()</span>
<span class="n">lifeDict</span> <span class="o" style="color: #666666;">=</span> <span class="n">startingGridRandom</span><span class="p">(</span><span class="n">lifeDict</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;"># Assign random life</span></pre>
<br />
<br />
Now somewhere above the main function lets create a new function to carry out this task.<br />
<br />
def startingGridRandom(lifeDict):<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">gridDict</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">startingGridRandom</span><span class="p">(</span><span class="n">lifeDict</span><span class="p">):</span></pre>
<br />
<br />
For each item in the dictionary we want to assign it a 0 or a 1. This is really easy. Again we are using a for loop to iterate through our dictionary. Once we have finished we return the dictionary.<br />
<br />
for item in lifeDict:<br />
lifeDict[item] = random.randint(0,1)<br />
return lifeDict<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">startingGridRandom</span><span class="p">(</span><span class="n">lifeDict</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">lifeDict</span><span class="p">:</span>
<span class="n">lifeDict</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="n">random</span><span class="o" style="color: #666666;">.</span><span class="n">randint</span><span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span><span class="mi" style="color: #40a070;">1</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">lifeDict</span></pre>
<br />
<br />
lifeDict[item] = random.randint(0,1) assigns randomly either a 0 or a 1 to the current item in lifeDict. As we are in a for loop looping through all items we should assign a 0 or a 1 to all items in the dictionary.<br />
<br />
random.randint uses the random libraries, which are not a standard part of python. We need to make sure we import these. So at the very top where we imported the pygame and sys libraries type.<br />
<br />
import random<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">pygame</span><span class="o" style="color: #666666;">,</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">sys</span>
<span class="kn" style="color: #007020; font-weight: bold;">from</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">pygame.locals</span> <span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="o" style="color: #666666;">*</span>
<span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">random</span></pre>
<br />
<br />
Now we have a grid drawn, we have created a dictionary which maps out if all the cells are alive or dead and we have randomly assigned life to each of the squares. Next we have to visually represent life, and we can do that by colouring in the squares which are alive a different colour, and ensuring those which should have a dead cell are displayed as white.<br />
<br />
Lets make our living cells green.<br />
<br />
The first thing we need to do is to assign a GREEN global variable. We know the three numbers make up Red, Green and Blue, so green will need the numbers, (0, 255, 0)<br />
<br />
GREEN = (0, 255, 0)<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"></pre>
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="c" style="color: #60a0b0; font-style: italic;"># set up the colors</span>
<span class="n">BLACK</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="mi" style="color: #40a070;">0</span><span class="p">)</span>
<span class="n">WHITE</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="mi" style="color: #40a070;">255</span><span class="p">)</span>
<span class="n">DARKGRAY</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">40</span><span class="p">,</span> <span class="mi" style="color: #40a070;">40</span><span class="p">,</span> <span class="mi" style="color: #40a070;">40</span><span class="p">)</span>
<span class="n">GREEN</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="mi" style="color: #40a070;">0</span><span class="p">,</span> <span class="mi" style="color: #40a070;">255</span><span class="p">,</span><span class="mi" style="color: #40a070;">0</span><span class="p">)</span></pre>
<br />
<br />
Now back into the main function. Straight after we have assigned the random grid, lets call a function to set each cell the right colour.<br />
<br />
for item in lifeDict:<br />
colourGrid(item, lifeDict)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"><br /></span>
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="n">lifeDict</span> <span class="o" style="color: #666666;">=</span> <span class="n">startingGridRandom</span><span class="p">(</span><span class="n">lifeDict</span><span class="p">)</span> <span class="c" style="color: #60a0b0; font-style: italic;"># Assign random life</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">lifeDict</span><span class="p">:</span>
<span class="n">colourGrid</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">lifeDict</span><span class="p">)</span></pre>
<br />
<br />
This calls the function colourGrid for each item. It passes the item through to the function, so we know which item we are dealing with, it also passes the dictionary to the function, which has all the information about the items being alive or dead.<br />
<br />
We will now write the colourGrid function with all the other functions.<br />
<br />
def colourGrid(item, lifeDict):<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">lifeDict</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">colourGrid</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">lifeDict</span><span class="p">):</span></pre>
<br />
<br />
The first line names the function and tells it what information it expects to be passed into the function.<br />
<br />
An item is made up of an x and a y component, lets seperate these out to make it easier to understand what we are referring to.<br />
<br />
x = item[0]<br />
y = item[1]<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">colourGrid</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">lifeDict</span><span class="p">):</span>
<span class="n">x</span> <span class="o" style="color: #666666;">=</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span>
<span class="n">y</span> <span class="o" style="color: #666666;">=</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span></pre>
<br />
<br />
At the moment we are still refering to our cells as the number they are positioned relative to the x and y axis. But we know we have created a CELLSIZE variable to allow us to make the cells which are displayed graphically, larger or smaller. So when we go to colour in the cells we need to take into account the fact that the cells are a certain size. We do this by multiplying the cell number by CELLSIZE to determine where to start drawing.<br />
<br />
y = y * CELLSIZE # translates array into grid size<br />
x = x * CELLSIZE # translates array into grid size<br />
<span class="Apple-tab-span" style="white-space: pre;"><br /></span>
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">y</span> <span class="o" style="color: #666666;">=</span> <span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span>
<span class="n">y</span> <span class="o" style="color: #666666;">=</span> <span class="n">y</span> <span class="o" style="color: #666666;">*</span> <span class="n">CELLSIZE</span> <span class="c" style="color: #60a0b0; font-style: italic;"># translates array into grid size</span>
<span class="n">x</span> <span class="o" style="color: #666666;">=</span> <span class="n">x</span> <span class="o" style="color: #666666;">*</span> <span class="n">CELLSIZE</span> <span class="c" style="color: #60a0b0; font-style: italic;"># translates array into grid size</span></pre>
<br />
<br />
Now we need to work out if the item should be green or white, depending if it is dead or alive. Starting with the dead cells.<br />
<br />
if lifeDict[item] ==0:<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">x</span> <span class="o" style="color: #666666;">=</span> <span class="n">x</span> <span class="o" style="color: #666666;">*</span> <span class="n">CELLSIZE</span> <span class="c" style="color: #60a0b0; font-style: italic;"># translates array into grid size</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">lifeDict</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">0</span><span class="p">:</span></pre>
<br />
<br />
Now we draw a rectangle in white using the co-ordinates and the size of the cell to determine the position of it.<br />
<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>pygame.draw.rect(DISPLAYSURF, WHITE, (x, y, CELLSIZE, CELLSIZE))<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">lifeDict</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">0</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">CELLSIZE</span><span class="p">,</span> <span class="n">CELLSIZE</span><span class="p">))</span></pre>
<br />
<br />
Repeating the process for the cells which are alive is similar, but we want to colour these green.<br />
<br />
<br />
if lifeDict[item] == 1:<br />
pygame.draw.rect(DISPLAYSURF, GREEN, (x, y, CELLSIZE, CELLSIZE))<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">WHITE</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">CELLSIZE</span><span class="p">,</span> <span class="n">CELLSIZE</span><span class="p">))</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">lifeDict</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">GREEN</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">CELLSIZE</span><span class="p">,</span> <span class="n">CELLSIZE</span><span class="p">))</span></pre>
<br />
<br />
Finally we return None.<br />
<br />
return None<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">GREEN</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">CELLSIZE</span><span class="p">,</span> <span class="n">CELLSIZE</span><span class="p">))</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span></pre>
<br />
Pressing F5 to save and run the program you should see a screen which looks something like this.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1ejP-QSzIaGypf3tMxty9GtEtJXFhGuXXNa0mWthevdlhlHy03-8VHf2-uFYzXhY3D2HIlh5OFBk631xf04OC17ApYCN045AY9ymJ8FKUZSZtHk7y12siwz-1OH8ezvhg-qV3g4H1TRE/s1600/GoL_Random.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1ejP-QSzIaGypf3tMxty9GtEtJXFhGuXXNa0mWthevdlhlHy03-8VHf2-uFYzXhY3D2HIlh5OFBk631xf04OC17ApYCN045AY9ymJ8FKUZSZtHk7y12siwz-1OH8ezvhg-qV3g4H1TRE/s320/GoL_Random.PNG" width="320" /></a></div>
<br />
<br />
<a href="https://docs.google.com/file/d/0B87aGq7vEpoFOUJuUl9ZWDhKU00/edit?usp=sharing" target="_blank">Random Colours Source Code</a><br />
<br />
<h3>
Stage 4 - Working Game of Life</h3>
<div>
<br /></div>
This takes us onto the final stage which is now letting the cells we have generated get on with the Game of Life.<br />
<br />
We know there are 4 rules to the game of life. As a reminder these are:<br />
<br />
1. Any live cell with fewer than two live neighbours dies, as if caused by under-population.<br />
2. Any live cell with two or three live neighbours lives on to the next generation.<br />
3. Any live cell with more than three live neighbours dies, as if by overcrowding.<br />
4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.<br />
<br />
We can see that what happens to a cell is very much dependant upon how many neighbours it has. Therefore a function to count all the neighbours of a cell would be useful. Lets write that now.<br />
<br />
We will create a function called getNeighbours. The function will need to know for which cell we want to get the neighbours, and the state of all the other cells. Therefore we will pass into the function the current cell and the dictionary of all cells.<br />
<br />
Place this function with all the other functions. <br />
<br />
def getNeighbours (item, lifeDict):<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">draw</span><span class="o" style="color: #666666;">.</span><span class="n">rect</span><span class="p">(</span><span class="n">DISPLAYSURF</span><span class="p">,</span> <span class="n">GREEN</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">CELLSIZE</span><span class="p">,</span> <span class="n">CELLSIZE</span><span class="p">))</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="bp" style="color: #007020;">None</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">getNeighbours</span><span class="p">(</span><span class="n">item</span><span class="p">,</span><span class="n">lifeDict</span><span class="p">):</span></pre>
<br />
The purpose of this function is to keep count of the number of neighbours which contain live cells, so lets create a variable to do that.<br />
<br />
neighbours = 0<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">getNeighbours</span><span class="p">(</span><span class="n">item</span><span class="p">,</span><span class="n">lifeDict</span><span class="p">):</span>
<span class="n">neighbours</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span></pre>
<br />
<br />
We know that for each cell there are 8 potential neighbours.<br />
<br />
<br />
x - 1 | x = 0 | x + 1<br />
y - 1 | y - 1 | y - 1<br />
------+-------+------<br />
x - 1 | x | x + 1<br />
y = 0 | y | y = 0<br />
------+-------+------<br />
x - 1 | x = 0 | x + 1<br />
y + 1 | y + 1 | y + 1<br />
<br />
By using our technique of a for loop within a for loop we should be able to iterate through all these with very little code.<br />
<br />
for x in range (-1, 2):<br />
for y in range (-1, 2):<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"><br /></span>
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">neighbours</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">x</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span> <span class="p">(</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">):</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">y</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span> <span class="p">(</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">):</span></pre>
<br />
<br />
This will give us 9 results, as it will include x = 0 and y = 0 which is our origonal cell. We don't want to class that as a neighbour, so we will deal with that later.<br />
<br />
We now want to use either the -1, 0 or + 1 for both x and y and if we add these onto the co-ordinates for the cell we are checking we should see all surrounding cells. <br />
<br />
Lets make a variable to highlight which cell we are actually checking.<br />
<br />
checkCell = (item[0]+x,item[1]+y)<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">y</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="nb" style="color: #007020;">range</span> <span class="p">(</span><span class="o" style="color: #666666;">-</span><span class="mi" style="color: #40a070;">1</span><span class="p">,</span><span class="mi" style="color: #40a070;">2</span><span class="p">):</span>
<span class="n">checkCell</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="n">x</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="n">y</span><span class="p">)</span></pre>
<br />
<br />
Wait a minute! Is there a potential problem? What if we are checking a cell which is at the left side of our grid? We would not be able to check any values for x - 1 as these would be off the side of our window we have created. This could cause our program to crash.<br />
<br />
Let us ignore any cells which are outside of the playing area, so we wont try to count any of these as neighbours.<br />
<br />
We will use an if statement to check both the width and the height.<br />
<br />
We know for the width our cells start at 0 on the left and finish at the value stored in CELLWIDTH on the right. Let us check to ensure our cells fall within that boundary.<br />
<br />
if checkCell[0] < CELLWIDTH and checkCell[0] >=0:<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">checkCell</span> <span class="o" style="color: #666666;">=</span> <span class="p">(</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="n">x</span><span class="p">,</span><span class="n">item</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">+</span><span class="n">y</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">checkCell</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;"><</span> <span class="n">CELLWIDTH</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">checkCell</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">>=</span><span class="mi" style="color: #40a070;">0</span><span class="p">:</span></pre>
<br />
<br />
This asks if the cell is less than the CELLWIDTH, AND greater than 0<br />
<br />
If the cell we are checking passes this criteria, lets now test it fits in the height of the grid.<br />
<br />
if checkCell [1] < CELLHEIGHT and checkCell[1]>= 0:<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">checkCell</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;"><</span> <span class="n">CELLWIDTH</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">checkCell</span><span class="p">[</span><span class="mi" style="color: #40a070;">0</span><span class="p">]</span> <span class="o" style="color: #666666;">>=</span><span class="mi" style="color: #40a070;">0</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">checkCell</span> <span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;"><</span> <span class="n">CELLHEIGHT</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">checkCell</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">>=</span> <span class="mi" style="color: #40a070;">0</span><span class="p">:</span></pre>
<br />
<br />
Any cell which has made it past both these if statements should be on our actual grid.<br />
<br />
Now we can interogate the cell we are checking and see if it has life in it. The whole purpose of this was to count any life in the surrounding cells.<br />
<br />
if lifeDict[checkCell] == 1:<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">checkCell</span> <span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span> <span class="o" style="color: #666666;"><</span> <span class="n">CELLHEIGHT</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">checkCell</span><span class="p">[</span><span class="mi" style="color: #40a070;">1</span><span class="p">]</span><span class="o" style="color: #666666;">>=</span> <span class="mi" style="color: #40a070;">0</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">lifeDict</span><span class="p">[</span><span class="n">checkCell</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span></pre>
<br />
<br />
So if there is a 1 in this field, we can say there is life, so can class that as a neighbour. Well not quite yet... As I mentioned earlier our two for loops are checking the eight neighbours and the central cell for neighbours. If we are looking at the central cell, then this is not a neighbouring cell it is our actual cell! So we should ignore this.<br />
<br />
if x == 0 and y == 0: # negate the central cell<br />
neighbours += 0<br />
else:<br />
neighbours += 1<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">lifeDict</span><span class="p">[</span><span class="n">checkCell</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">x</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">0</span> <span class="ow" style="color: #007020; font-weight: bold;">and</span> <span class="n">y</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">0</span><span class="p">:</span>
<span class="n">neighbours</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">neighbours</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span></pre>
<br />
<br />
This will only count neighbours in the surrounding 8 cells and not in the actual cell itself.<br />
<br />
Finally we return the number of neighbours.<br />
<br />
return neighbours.<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">neighbours</span> <span class="o" style="color: #666666;">+=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">neighbours</span></pre>
<br />
<br />
We know on our grid where the alive cells are. We also have a method of determining the number of neighbours each cell has. All we need to do now is act on that information and determine what happens in the next generation, which is sometimes referred to as a tick in the Game of Life.<br />
<br />
Lets write a function to determine what happens every tick. This function is the main crux of the program, but is very easy to write!<br />
<br />
def tick (lifeDict):<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">neighbours</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">tick</span><span class="p">(</span><span class="n">lifeDict</span><span class="p">):</span></pre>
<br />
<br />
Lets create a function called tick, and pass in the dictionary of all our life cells.<br />
<br />
Our four rules need to apply to all the cells at once. To avoid us writing over current data, which would alter the results, lets create a temporary dictionary to store the information about the next generation or tick.<br />
<br />
newTick = {}<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">tick</span><span class="p">(</span><span class="n">lifeDict</span><span class="p">):</span>
<span class="n">newTick</span> <span class="o" style="color: #666666;">=</span> <span class="p">{}</span></pre>
<br />
<br />
Now we should look at each cell within our population.<br />
<br />
for item in lifeDict:<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">newTick</span> <span class="o" style="color: #666666;">=</span> <span class="p">{}</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">lifeDict</span><span class="p">:</span></pre>
<br />
<br />
We can determine the number of neighbours by calling the function we wrote earlier which returns the number of neighbours.<br />
<br />
numberNeighbours = getNeighbours(item, lifeDict)<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">lifeDict</span><span class="p">:</span>
<span class="n">numberNeighbours</span> <span class="o" style="color: #666666;">=</span> <span class="n">getNeighbours</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">lifeDict</span><span class="p">)</span></pre>
<br />
<br />
Three of the rules refer to the cells which are alive, which we have denoted as a 1. Lets deal with those first.<br />
<br />
if lifeDict[item] == 1:<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">numberNeighbours</span> <span class="o" style="color: #666666;">=</span> <span class="n">getNeighbours</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">lifeDict</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">lifeDict</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span></pre>
<br />
<br />
We know if the population is less than 2, then the cell will die due to under population. We do a simple test and store the result of a dead cell (a 0) into the temporary newTick dictionary.<br />
<br />
if numberNeighbours < 2:<br />
newTick[item] = 0<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">lifeDict</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">1</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;"># For those cells already alive</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">numberNeighbours</span> <span class="o" style="color: #666666;"><</span> <span class="mi" style="color: #40a070;">2</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;"># kill under-population</span>
<span class="n">newTick</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span></pre>
<br />
<br />
If the number of neighbours is larger than 3 there is over crowding, again resulting in a dead cell.<br />
<br />
elif numberNeighbours > 3:<br />
newTick[item] = 0<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"><br /></span>
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">numberNeighbours</span> <span class="o" style="color: #666666;"><</span> <span class="mi" style="color: #40a070;">2</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;"># kill under-population</span>
<span class="n">newTick</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">numberNeighbours</span> <span class="o" style="color: #666666;">></span> <span class="mi" style="color: #40a070;">3</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;">#kill over-population</span>
<span class="n">newTick</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span></pre>
<br />
<br />
We have dealt with less than 2 and greater than 3 neighbours. However not specified what happens to those cells with 2 or 3 neighbours.<br />
<br />
Well these survive.<br />
<br />
else:<br />
newTick[item] = 1 # keep status quo (life)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"><br /></span>
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">numberNeighbours</span> <span class="o" style="color: #666666;">></span> <span class="mi" style="color: #40a070;">3</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;">#kill over-population</span>
<span class="n">newTick</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">newTick</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span> <span class="c" style="color: #60a0b0; font-style: italic;"># keep status quo (life)</span></pre>
<br />
<br />
The else part of the if statement covers all other options which will be either 2 or 3.<br />
<br />
Now lets look at the possible options if the cell is currently dead.<br />
<br />
elif lifeDict[item] == 0:<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">newTick</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span> <span class="c" style="color: #60a0b0; font-style: italic;"># keep status quo (life)</span>
<span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">lifeDict</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">0</span><span class="p">:</span></pre>
<br />
<br />
It will become alive if there are exactly three neighbours which are alive.<br />
<br />
if numberNeighbours == 3: # cell reproduces<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>newTick[item] = 1<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"><br /></span>
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">elif</span> <span class="n">lifeDict</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">0</span><span class="p">:</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">numberNeighbours</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">3</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;"># cell reproduces</span>
<span class="n">newTick</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span></pre>
<br />
<br />
Otherwise it will remain devoid of life....<br />
<br />
else:<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>newTick[item] = 0 # keep status quo (death)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"><br /></span>
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">numberNeighbours</span> <span class="o" style="color: #666666;">==</span> <span class="mi" style="color: #40a070;">3</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;"># cell reproduces</span>
<span class="n">newTick</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">1</span>
<span class="k" style="color: #007020; font-weight: bold;">else</span><span class="p">:</span>
<span class="n">newTick</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span> <span class="c" style="color: #60a0b0; font-style: italic;"># keep status quo (death)</span></pre>
<br />
<br />
Thats all the options dealt with. It should have been determined what the new state for every position on the newGrid should be, so lets now return the dictionary with this information.<br />
<br />
return newTick<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="n">newTick</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">0</span> <span class="c" style="color: #60a0b0; font-style: italic;"># keep status quo (death)</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">newTick</span></pre>
<br />
<br />
So far in our main function we have been preparing the grid and getting it ready to play the game. But we have not placed anything within the continuous loop which allows the game to keep running. It is the creating of this new generation or tick which should be placed in that while loop.<br />
<br />
lifeDict = tick(lifeDict)<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">while</span> <span class="bp" style="color: #007020;">True</span><span class="p">:</span> <span class="c" style="color: #60a0b0; font-style: italic;">#main game loop</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">event</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">get</span><span class="p">():</span>
<span class="k" style="color: #007020; font-weight: bold;">if</span> <span class="n">event</span><span class="o" style="color: #666666;">.</span><span class="n">type</span> <span class="o" style="color: #666666;">==</span> <span class="n">QUIT</span><span class="p">:</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">quit</span><span class="p">()</span>
<span class="n">sys</span><span class="o" style="color: #666666;">.</span><span class="n">exit</span><span class="p">()</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#runs a tick</span>
<span class="n">lifeDict</span> <span class="o" style="color: #666666;">=</span> <span class="n">tick</span><span class="p">(</span><span class="n">lifeDict</span><span class="p">)</span></pre>
<br />
<br />
We are replacing the information of our current generation with the information from the new generation we have determined.<br />
<br />
Now our dictionary contains the information for the new generation, lets run through all the cells and ensure they are all coloured in correctly.<br />
<br />
for item in lifeDict:<br />
colourGrid(item, lifeDict)<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"><br /></span>
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="c" style="color: #60a0b0; font-style: italic;">#runs a tick</span>
<span class="n">lifeDict</span> <span class="o" style="color: #666666;">=</span> <span class="n">tick</span><span class="p">(</span><span class="n">lifeDict</span><span class="p">)</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Colours the live cells, blanks the dead</span>
<span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">lifeDict</span><span class="p">:</span>
<span class="n">colourGrid</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">lifeDict</span></pre>
<br />
<br />
We have done this before when colouring in our random starting grid, but this ensures it is done each generation.<br />
<br />
Finally we need to specify how often we want the screen to update with our new information. We can set a value of FPS or Frames Per Second to do this.<br />
<br />
So with your global variables type:<br />
<br />
FPS = 10<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"><span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">random</span>
<span class="c" style="color: #60a0b0; font-style: italic;">#Number of frames per second</span>
<span class="n">FPS</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #40a070;">10</span></pre>
<br />
<br />
In our main function we need to specify the clock which will control the speed of the ticks.<br />
<br />
FPSCLOCK = pygame.time.Clock()<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">global</span> <span class="n">DISPLAYSURF</span>
<span class="n">FPSCLOCK</span> <span class="o" style="color: #666666;">=</span> <span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">time</span><span class="o" style="color: #666666;">.</span><span class="n">Clock</span><span class="p">()</span></pre>
<br />
<br />
Now lets make sure our while loop runs a new tick referring to the FPS.<br />
<br />
To do this at the bottom of your while loop add the following line<br />
<br />
FPSCLOCK.tick(FPS)<br />
<br />
<br />
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"> <span class="k" style="color: #007020; font-weight: bold;">for</span> <span class="n">item</span> <span class="ow" style="color: #007020; font-weight: bold;">in</span> <span class="n">lifeDict</span><span class="p">:</span>
<span class="n">colourGrid</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">lifeDict</span><span class="p">)</span>
<span class="n">drawGrid</span><span class="p">()</span>
<span class="n">pygame</span><span class="o" style="color: #666666;">.</span><span class="n">display</span><span class="o" style="color: #666666;">.</span><span class="n">update</span><span class="p">()</span>
<span class="n">FPSCLOCK</span><span class="o" style="color: #666666;">.</span><span class="n">tick</span><span class="p">(</span><span class="n">FPS</span><span class="p">)</span></pre>
<pre style="border: none; font-family: 'Bitstream Vera Sans Mono', monospace; font-size: 13px; overflow: auto; padding: 10px;"></pre>
<br />
If you want to slow or speed up the Game of Life you can do this by modifying the global FPS value. However it will only run as fast as your computer can cope with!<br />
<br />
Run the game and you should see cells living and dying right in front of your eyes!<br />
<br />
If you would like full source code for the game of life it can be found here.<br />
<br />
<a href="https://docs.google.com/file/d/0B87aGq7vEpoFWVZKaWgtLXdFTTg/edit?usp=sharing" target="_blank">Game of Life Source Code</a><br />
<br />
I hope you have enjoyed this tutorial. When I said at the start of this that I felt the Game of Life was too difficult for me to write, I was wrong... If you break everything down into manageable chunks like I have shown here, there is nothing difficult about it.<br />
<br />
For those of you interested I have create a second blog on this topic. This moves away from a random starting point shown here, and demonstrates some of the more interesting controlled starts. The link is below.<br />
<br />
<a href="http://trevorappleton.blogspot.co.uk/2013/07/python-game-of-life-alternative-starts.html" target="_blank">Game of Life - Alternative Starts</a>Trevor Appletonhttp://www.blogger.com/profile/17443416480215610122noreply@blogger.com10