<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.0">Jekyll</generator><link href="http://katieamazing.com/feed.xml" rel="self" type="application/atom+xml" /><link href="http://katieamazing.com/" rel="alternate" type="text/html" /><updated>2021-11-06T17:18:43+00:00</updated><id>http://katieamazing.com/feed.xml</id><title type="html">Katie Amazing</title><subtitle>Personal website/blog</subtitle><entry><title type="html">2017 Conference Rundown</title><link href="http://katieamazing.com/blog/2017/12/20/conference-rundown-2017" rel="alternate" type="text/html" title="2017 Conference Rundown" /><published>2017-12-20T00:00:00+00:00</published><updated>2017-12-20T00:00:00+00:00</updated><id>http://katieamazing.com/blog/2017/12/20/conference-rundown-2017</id><content type="html" xml:base="http://katieamazing.com/blog/2017/12/20/conference-rundown-2017">&lt;p&gt;&lt;strong&gt;April
Codeland 2017 - New York, New York&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Codeland was a bit of an emotional mix for me: it was inspiring and welcoming, but at the same time I felt out of place. The conference is geared toward Code Newbies, and this was the first moment I realized that I was definitely not a newbie any longer. A highlight was meeting Katrina Owen, who was speaking, and who cowrote a &lt;a href=&quot;https://www.sandimetz.com/99bottles/&quot;&gt;book&lt;/a&gt; I had read recently and who is the founder of &lt;a href=&quot;http://exercism.io/&quot;&gt;exercism.io&lt;/a&gt;, a significant part of my coding journey. She is one of my heroes who has directly made programming more accessible to me. In a casual conversation, she graciously encouraged me to consider putting together a conference talk on a project I shared with her. Her encouragement and feeling like less of a newbie really got the gears turning in my head - maybe 2018 is the year of speaking at rather than attending conferences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;May
!!Con 2017 - New York, New York&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;!!Con was great again this year. The speakers are always diverse and fascinating, and the frenetic fun of 10-minute talks keeps the energy high all day. I really appreciated that there was more unconferencing social time during the conference this year; it let me chat to some nice people, reconnect to old people in my technical network, and meet some new RC people in meat-space. My experience at !!Con was super different than last year - I followed technical aspects of talks better, felt less mind-blown all the time (or at least, the mind-blowing had an “OMG COOL” feel rather than an “OMG I am so lost” feel), and I was more confident introducing myself to strangers as a programmer. It was a good benchmarking experience for me to feel how much I have grown as a programmer and technical person in a year. I’ll definitely try to attend in 2018, but tickets are pretty tough to come by, and I felt lucky this year to get one!&lt;/p&gt;

&lt;p&gt;I also got to meet Mirabai again this year. &lt;a href=&quot;twitter,com/stenoknight&quot;&gt;Mirabai&lt;/a&gt; does live captioning for conferences on her stenography machine. She is basically a pinball-wizard crossed with an arch-mage, and is also somehow super nice. Her passion for stenography and the relatively nascent efforts to support it with open source hardware and software were totally infectious. Meeting her again got me excited to try and learn stenography, so I’m currently eagerly awaiting a 3D printed steno board.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PyCon 2017 - Portland, Oregon&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PyCon 2017 was an amazing experience. After having so many conference jammed into my spring schedule, I was feeling a little conferenced-out. So I gave myself permission to go all in on the “hallway track”. I attended only one (1) live talk! After the conference, I went back and watched some of the talks that seemed the most useful to me on YouTube. During the conference, I hung out with friends, networked with companies and open source maintainers, and enjoyed PyCon’s robust Open Spaces events and Lightning Talks. I got to meet Russell Keith-Magee, the owner of the BeeWare project, who I heard speak about his BeeWare Toga project at last year’s PyGotham 2016, and getting to know him as a new contributor to the BeeWare VOC project felt as if a lot of things had come full circle for me in a very positive way.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/katieamazing/katieamazing.github.io/raw/master/img/IMG_20170519_092609190_TOP-(1).jpg&quot; alt=&quot;Got a challenge coin for my BeeWare contributions&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I did have a weird sense of being less of the Python tribe than many who attended. A lot of people who go to PyCon seem like they have really drunk the Python Kool-Aid, and use Python as a tool for absolutely everything because they are fond of and expert with the language. As someone who identifies as a polyglot programmer, I found it a bit baffling at times the contortions people get into so they can use Python for everything. It was an interesting takeaway - learning about the power of Python, but also seeing that there are limits and that it might not been the best tool for all things (though this was a conclusion I came to myself, not one espoused by anyone I heard or spoke to).&lt;/p&gt;

&lt;p&gt;It was a lot of socializing, which I found exhausting but also really enjoyable and valuable. The Python community is intensely supportive, kind, outgoing, etc. I also got to meet a number of Recursers who had traveled to Portland. I wish I could have stayed for the sprints during the week following the conference, as contributing in that setting to the BeeWare project would have been valuable, but Recurse was back in session on Monday. Maybe next year!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;September 
Owning Your Experience by Write/Speak/Code - New York, New York&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This one-day intensive for women and nonbinary people was part-workshop, part extended talk. The material focused on owning power, leveraging experience, and ways to demonstrate and amplify those to the world. I ran into a lot of great women I already knew, and met many new people. It was nice to talk with women from all over the tech world, in varying specialities, and with different experience levels. I was a little disappointed that the impressive mentors for the day didn’t have much stage time to talk about themselves and their experiences, and that we didn’t do as much coding as I imagined we might do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ElmConf and Strange Loop 2017 - St. Louis, Missouri&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ElmConf was an interesting experience. It underlined to me that Elm is a young technology and a small community; most of the speakers were maintainers of Elm packages, maybe had a bit less star-power than I have become accustomed to from conferences. The talks were interesting and I learned some new things about union types and integrating Elm with APIs.&lt;/p&gt;

&lt;p&gt;The actual StrangeLoop conference was fantastic. I enjoyed the NES talk, which was very reminiscent of an extended !!Con talk. I was interested to hear about some newer languages, like Lux, Datafun, and Kotlin. Heard a good talk about web authentication (It Me) and building for chaos - but I tried to remember, my projects are not Netflix-scale.&lt;/p&gt;

&lt;p&gt;This was a less social and less fully committed conference on my part. I had some personal stuff going on before and during the trip that left me with less energy and time to be social. Those factors affected my enjoyment of this conference. St. Louis was a cool place to visit, though, and the venue was wonderful, the party was really fun, and the hotel was super beautiful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PyGotham 2017 - New York, New York&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I made it to the first day of PyGotham this year before being taken down by the flu. It was wonderful to see lots of my Python friends, hear some cool talks, and make a bit of progress on my job hunting.&lt;/p&gt;

&lt;p&gt;I enjoyed hearing about algorithmic transparency and getting exposed to new data science stuff, learning more about the Raft consensus algorithm from a Python friend’s first talk (!), and I felt that I got a lot out of the excellent &lt;a href=&quot;https://www.harihareswara.net/&quot;&gt;Sumana’s&lt;/a&gt; talk which took the form of a play and demonstrated various approaches and dialogues one might encounter in a professional setting as a programmer with code to review.&lt;/p&gt;</content><author><name></name></author><summary type="html">April Codeland 2017 - New York, New York Codeland was a bit of an emotional mix for me: it was inspiring and welcoming, but at the same time I felt out of place. The conference is geared toward Code Newbies, and this was the first moment I realized that I was definitely not a newbie any longer. A highlight was meeting Katrina Owen, who was speaking, and who cowrote a book I had read recently and who is the founder of exercism.io, a significant part of my coding journey. She is one of my heroes who has directly made programming more accessible to me. In a casual conversation, she graciously encouraged me to consider putting together a conference talk on a project I shared with her. Her encouragement and feeling like less of a newbie really got the gears turning in my head - maybe 2018 is the year of speaking at rather than attending conferences. May !!Con 2017 - New York, New York !!Con was great again this year. The speakers are always diverse and fascinating, and the frenetic fun of 10-minute talks keeps the energy high all day. I really appreciated that there was more unconferencing social time during the conference this year; it let me chat to some nice people, reconnect to old people in my technical network, and meet some new RC people in meat-space. My experience at !!Con was super different than last year - I followed technical aspects of talks better, felt less mind-blown all the time (or at least, the mind-blowing had an “OMG COOL” feel rather than an “OMG I am so lost” feel), and I was more confident introducing myself to strangers as a programmer. It was a good benchmarking experience for me to feel how much I have grown as a programmer and technical person in a year. I’ll definitely try to attend in 2018, but tickets are pretty tough to come by, and I felt lucky this year to get one! I also got to meet Mirabai again this year. Mirabai does live captioning for conferences on her stenography machine. She is basically a pinball-wizard crossed with an arch-mage, and is also somehow super nice. Her passion for stenography and the relatively nascent efforts to support it with open source hardware and software were totally infectious. Meeting her again got me excited to try and learn stenography, so I’m currently eagerly awaiting a 3D printed steno board. PyCon 2017 - Portland, Oregon PyCon 2017 was an amazing experience. After having so many conference jammed into my spring schedule, I was feeling a little conferenced-out. So I gave myself permission to go all in on the “hallway track”. I attended only one (1) live talk! After the conference, I went back and watched some of the talks that seemed the most useful to me on YouTube. During the conference, I hung out with friends, networked with companies and open source maintainers, and enjoyed PyCon’s robust Open Spaces events and Lightning Talks. I got to meet Russell Keith-Magee, the owner of the BeeWare project, who I heard speak about his BeeWare Toga project at last year’s PyGotham 2016, and getting to know him as a new contributor to the BeeWare VOC project felt as if a lot of things had come full circle for me in a very positive way. I did have a weird sense of being less of the Python tribe than many who attended. A lot of people who go to PyCon seem like they have really drunk the Python Kool-Aid, and use Python as a tool for absolutely everything because they are fond of and expert with the language. As someone who identifies as a polyglot programmer, I found it a bit baffling at times the contortions people get into so they can use Python for everything. It was an interesting takeaway - learning about the power of Python, but also seeing that there are limits and that it might not been the best tool for all things (though this was a conclusion I came to myself, not one espoused by anyone I heard or spoke to). It was a lot of socializing, which I found exhausting but also really enjoyable and valuable. The Python community is intensely supportive, kind, outgoing, etc. I also got to meet a number of Recursers who had traveled to Portland. I wish I could have stayed for the sprints during the week following the conference, as contributing in that setting to the BeeWare project would have been valuable, but Recurse was back in session on Monday. Maybe next year! September Owning Your Experience by Write/Speak/Code - New York, New York This one-day intensive for women and nonbinary people was part-workshop, part extended talk. The material focused on owning power, leveraging experience, and ways to demonstrate and amplify those to the world. I ran into a lot of great women I already knew, and met many new people. It was nice to talk with women from all over the tech world, in varying specialities, and with different experience levels. I was a little disappointed that the impressive mentors for the day didn’t have much stage time to talk about themselves and their experiences, and that we didn’t do as much coding as I imagined we might do. ElmConf and Strange Loop 2017 - St. Louis, Missouri ElmConf was an interesting experience. It underlined to me that Elm is a young technology and a small community; most of the speakers were maintainers of Elm packages, maybe had a bit less star-power than I have become accustomed to from conferences. The talks were interesting and I learned some new things about union types and integrating Elm with APIs. The actual StrangeLoop conference was fantastic. I enjoyed the NES talk, which was very reminiscent of an extended !!Con talk. I was interested to hear about some newer languages, like Lux, Datafun, and Kotlin. Heard a good talk about web authentication (It Me) and building for chaos - but I tried to remember, my projects are not Netflix-scale. This was a less social and less fully committed conference on my part. I had some personal stuff going on before and during the trip that left me with less energy and time to be social. Those factors affected my enjoyment of this conference. St. Louis was a cool place to visit, though, and the venue was wonderful, the party was really fun, and the hotel was super beautiful. PyGotham 2017 - New York, New York I made it to the first day of PyGotham this year before being taken down by the flu. It was wonderful to see lots of my Python friends, hear some cool talks, and make a bit of progress on my job hunting. I enjoyed hearing about algorithmic transparency and getting exposed to new data science stuff, learning more about the Raft consensus algorithm from a Python friend’s first talk (!), and I felt that I got a lot out of the excellent Sumana’s talk which took the form of a play and demonstrated various approaches and dialogues one might encounter in a professional setting as a programmer with code to review.</summary></entry><entry><title type="html">Sip Sip Universe, Ludum Dare 39</title><link href="http://katieamazing.com/blog/2017/10/08/LD39" rel="alternate" type="text/html" title="Sip Sip Universe, Ludum Dare 39" /><published>2017-10-08T00:00:00+00:00</published><updated>2017-10-08T00:00:00+00:00</updated><id>http://katieamazing.com/blog/2017/10/08/LD39</id><content type="html" xml:base="http://katieamazing.com/blog/2017/10/08/LD39">&lt;p&gt;Another Ludum Dare game jam happened a few weeks ago! As is typical, I did the jam (72 hours, slightly relaxed rules, teams allowed - hi &lt;a href=&quot;https://twitter.com/Johnicholas&quot;&gt;@Johnicholas&lt;/a&gt;). The theme was &lt;strong&gt;“running out of power”&lt;/strong&gt;. We got really lucky with the theme - we actually concepted this game about a week early, and hoped for a theme we could shoehorn in somehow. That worked out this time.&lt;/p&gt;

&lt;p&gt;I have been playing a lot of No Man’s Sky lately, so a space-exploring, procedurally-generated universe sounded fun to create. And we play a lot of a wonderful multiplayer game called &lt;a href=&quot;http://store.steampowered.com/app/226100/PixelJunk_Nom_Nom_Galaxy/&quot;&gt;Nom Nom Galaxy&lt;/a&gt;, a side-scrolling platformer where you explore planets, punch strange plants and animals, and make soup out of them. And so, additionally inspired by Sims2/3 winemaking, we mashed some of our favorite games together to make Sip Sip Universe: an adventure on procedurally generated planets to explore, pick fruits, and make wines.&lt;/p&gt;

&lt;p&gt;One of the concepts was to use some &lt;strong&gt;procedural generation&lt;/strong&gt; to multiply the assets. I created fruits and planets in multiple SVG layers using Inkscape, and programmatically selected layers and render colors. This really worked out, and we achieved a lot of variety:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/katieamazing/LD39/master/imgs/just_for_showoffs.jpg&quot; alt=&quot;planets&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Another concept was &lt;strong&gt;persisted multiplayer data&lt;/strong&gt; to allow players to name and store their wines in a “Winecellar Between the Worlds”. This added some permanence and interest to the process of making and naming bottles. I wrote a Lua backend on webscript.io to handle the data, which I had done before. The new part for me was sending the requests from Javascript. It was very satisfying to implement JS promises seamlessly, after some months of learning about them tangentially. Getting the dialog boxes to play nicely was challenging, and they still don’t look as slick as I imagined them - UI is hard, idk. Still, the wine descriptions that everyone could read did add a lot to the game and was a top highlight for many players.&lt;/p&gt;

&lt;p&gt;Exploring planets was a big part of the game concept, and unfortunately the area we made the deepest cuts to during the jam. While you can walk around and enjoy a partially programmatically-generated world while you collect fruits, we did not implement terrain collisions on the planet surface. We also considered having destructible terrain, as No Man’s Sky and Nom Nom Universe have. We also imagined having some enemies to fight or avoid. Lastly, we imagined an “underworld” that felt more like a cave spelunking or roguelike that the player might access through holes in the planet’s crust. We didn’t get anywhere near enough time for this in the original 72 hours!&lt;/p&gt;

&lt;p&gt;We also wanted planet and ingredient descriptions to have procedural descriptions and qualities. Another element that got cut for time was a music system.&lt;/p&gt;

&lt;p&gt;However, we continued work on this game in the following weeks, and I am pleased to present the Sip Sip Universe Platinum Post-Jam 2017 Thing of the Year Edition. This version uses webtask.io, a backend in JavaScript instead of Lua. I found it a much more challenging backend to use, but the switch was forced by webscript.io shutting down soon. This version does feature terrain collisions, an underworld with monsters, and music made by yours truly.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://katieamazing.com/games/Sip-Sip-Universe/&quot;&gt;&lt;img src=&quot;https://raw.githubusercontent.com/katieamazing/katieamazing.github.io/master/img/splash.jpg&quot; alt=&quot;a hyperlinked image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://katieamazing.com/games/Sip-Sip-Universe/&quot;&gt;Play the game here&lt;/a&gt; (probably only works on Chrome)!&lt;/p&gt;

&lt;p&gt;If you’d like to play the original jam version for cringe and/or comparison, find it &lt;a href=&quot;http://katieamazing.com/games/LD39/index.html&quot;&gt;here&lt;/a&gt;. Or if you would like to rate/comment on our entry, &lt;a href=&quot;https://ldjam.com/events/ludum-dare/39/sip-sip-universe&quot;&gt;here it is at the Ludum Dare site&lt;/a&gt;.&lt;/p&gt;</content><author><name></name></author><summary type="html">Another Ludum Dare game jam happened a few weeks ago! As is typical, I did the jam (72 hours, slightly relaxed rules, teams allowed - hi @Johnicholas). The theme was “running out of power”. We got really lucky with the theme - we actually concepted this game about a week early, and hoped for a theme we could shoehorn in somehow. That worked out this time. I have been playing a lot of No Man’s Sky lately, so a space-exploring, procedurally-generated universe sounded fun to create. And we play a lot of a wonderful multiplayer game called Nom Nom Galaxy, a side-scrolling platformer where you explore planets, punch strange plants and animals, and make soup out of them. And so, additionally inspired by Sims2/3 winemaking, we mashed some of our favorite games together to make Sip Sip Universe: an adventure on procedurally generated planets to explore, pick fruits, and make wines. One of the concepts was to use some procedural generation to multiply the assets. I created fruits and planets in multiple SVG layers using Inkscape, and programmatically selected layers and render colors. This really worked out, and we achieved a lot of variety: Another concept was persisted multiplayer data to allow players to name and store their wines in a “Winecellar Between the Worlds”. This added some permanence and interest to the process of making and naming bottles. I wrote a Lua backend on webscript.io to handle the data, which I had done before. The new part for me was sending the requests from Javascript. It was very satisfying to implement JS promises seamlessly, after some months of learning about them tangentially. Getting the dialog boxes to play nicely was challenging, and they still don’t look as slick as I imagined them - UI is hard, idk. Still, the wine descriptions that everyone could read did add a lot to the game and was a top highlight for many players. Exploring planets was a big part of the game concept, and unfortunately the area we made the deepest cuts to during the jam. While you can walk around and enjoy a partially programmatically-generated world while you collect fruits, we did not implement terrain collisions on the planet surface. We also considered having destructible terrain, as No Man’s Sky and Nom Nom Universe have. We also imagined having some enemies to fight or avoid. Lastly, we imagined an “underworld” that felt more like a cave spelunking or roguelike that the player might access through holes in the planet’s crust. We didn’t get anywhere near enough time for this in the original 72 hours! We also wanted planet and ingredient descriptions to have procedural descriptions and qualities. Another element that got cut for time was a music system. However, we continued work on this game in the following weeks, and I am pleased to present the Sip Sip Universe Platinum Post-Jam 2017 Thing of the Year Edition. This version uses webtask.io, a backend in JavaScript instead of Lua. I found it a much more challenging backend to use, but the switch was forced by webscript.io shutting down soon. This version does feature terrain collisions, an underworld with monsters, and music made by yours truly. Play the game here (probably only works on Chrome)! If you’d like to play the original jam version for cringe and/or comparison, find it here. Or if you would like to rate/comment on our entry, here it is at the Ludum Dare site.</summary></entry><entry><title type="html">Python-NLP Twitter Bots</title><link href="http://katieamazing.com/blog/2017/08/25/Python-Twitter-Bots" rel="alternate" type="text/html" title="Python-NLP Twitter Bots" /><published>2017-08-25T00:00:00+00:00</published><updated>2017-08-25T00:00:00+00:00</updated><id>http://katieamazing.com/blog/2017/08/25/Python-Twitter-Bots</id><content type="html" xml:base="http://katieamazing.com/blog/2017/08/25/Python-Twitter-Bots">&lt;p&gt;I recently launched two new Twitter bots! I guess, when Twitter bums me out for not meeting my quota of procedurally-generated silliness, I fill my feed with my own wacky creations.&lt;/p&gt;

&lt;p&gt;So, I’m glad to introduce &lt;strong&gt;&lt;a href=&quot;https://twitter.com/tsrewrite&quot;&gt;@tsrewrite&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href=&quot;https://twitter.com/pussy_bot&quot;&gt;@pussy_bot&lt;/a&gt;&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/tsrewrite&quot;&gt;&lt;img src=&quot;https://raw.githubusercontent.com/katieamazing/katieamazing.github.io/master/img/tsrewrite.png&quot; alt=&quot;tsrewrite&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;https://twitter.com/pussy_bot&quot;&gt;&lt;img src=&quot;https://raw.githubusercontent.com/katieamazing/katieamazing.github.io/master/img/pussy_bot.png&quot; alt=&quot;pussy_bot&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These bots were both written with Python, use the Twython library to interact with Twitter’s API, and are running as cron jobs on PythonAnywhere’s cloud.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pussy Bot&lt;/strong&gt; uses BeautifulSoup to parse an html document containing the text of the 1895 book &lt;em&gt;Pussy and Her Language&lt;/em&gt;, by Marvin R. Clark. The program filters each sentence in the book by a tweetable length, and by some keywords that have to do with cats. This cuts down on the possible tweets quite a lot, as it is a verbose example of writing. I anticipate at one daily tweet that the bot will start to repeat itself obviously in about six months, at which point I will have to expand my filtering parameters, or add new Victorian literature about cats. Each sentence is accompanied by mid-to-late 19th century and early 20th century fine artworks featuring cats, mostly pulled from Wikimedia Commons. The src is &lt;a href=&quot;https://github.com/katieamazing/pussybot&quot;&gt;here&lt;/a&gt;, if you are interested.&lt;/p&gt;
&lt;html&gt;&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;My greatest desire is to interest the world in this worthy subject and induce investigations by others. &lt;a href=&quot;https://t.co/zPUSi3NMvb&quot;&gt;pic.twitter.com/zPUSi3NMvb&lt;/a&gt;&lt;/p&gt;&amp;mdash; Victorian Cat Notes (@pussy_bot) &lt;a href=&quot;https://twitter.com/pussy_bot/status/896464020903014400&quot;&gt;August 12, 2017&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;&lt;/html&gt;

&lt;p&gt;&lt;strong&gt;Taylor Swift Rewrite&lt;/strong&gt; rewrites the earwormiest Taylor Swift lyrics with NLTK. The scipt generating the tweets has three functions which plug in generated words in a mad-libs fashion. The script chooses words randomly by their part of speech from the Wordnet corpus. Some words are filtered by their common-ness by comparing them to the Webtext corpus; this cuts down on jargon words and proper nouns. At one point in the development of the script, it squashed all weird words, but I found I liked some of them. So it is not fully applied to every generated word.&lt;/p&gt;

&lt;p&gt;Another feature of the bot’s word picking is the ability to take a selected word and find a related word, ideally creating a pair. These pairs can be related by rhyme, using &lt;a href=&quot;https://github.com/aparrish/pronouncingpy&quot;&gt;Allison Parrish’s excellent pronouncing library&lt;/a&gt; to find rhyming words. The pair can instead be related by meaning. I experimented with training my own models and using Word2Vec to use word vectors to find related words by meaning, but didn’t find the results accurate enough. So I have implemented the script with a pre-trained model from Google.&lt;/p&gt;

&lt;p&gt;The Google model’s results are much more accurate. Its thoroughness created a deployment issue, as my cloud solution will not tolerate a 1.5GB model running on it. For now, I run a local script once a month that generates the next month’s tweets, scan them with my human eyes :eyes: for anything potentially offensive, and upload the pickled file to the cloud. A script then accesses that file to tweet it through the month. The scripts powering the bot are &lt;a href=&quot;https://github.com/katieamazing/tsrewritebot&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;html&gt;&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;She watches economic geography,&lt;br /&gt;I background crate,&lt;br /&gt;She&amp;#39;s topography,&lt;br /&gt;I have all this weight.&lt;/p&gt;&amp;mdash; Taylor Swift Rewrite (@tsrewrite) &lt;a href=&quot;https://twitter.com/tsrewrite/status/900056032927510528&quot;&gt;August 22, 2017&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;&lt;/html&gt;

&lt;p&gt;I’d like to experiment with other NLP stuff on this bot, and hopefully move it to a less-manual process. Training a model on Taylor Swift lyrics and implementing a Markov Chain sounds fun, and might do some of the work my script is doing implicitly - like filtering for “normal human song lyric”-quality words.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://static.spin.com/files/tumblr_naiv0tkX2t1qh0wmfo1_400.gif&quot; alt=&quot;taylor swift is a robot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I have &lt;a href=&quot;http://katieamazing.com/blog/2016/01/20/tracery&quot;&gt;previously made a Twitter bot&lt;/a&gt; using JSON and &lt;a href=&quot;https://github.com/galaxykate/tracery&quot;&gt;Kate Compton’s Tracery&lt;/a&gt;, and while it felt creative, it did not feel much like writing code or like a technical challenge. Tracery and Cheap Bots Done Quick are such excellent tools that they take care of a lot of the pain for you. I enjoyed digging a little deeper into the process, even though Twython also makes things fairly painless.&lt;/p&gt;

&lt;p&gt;It was terrific using my Python skills to get these bots working, and I’m looking forward to enjoying them in my feed. I hope you’ll follow and enjoy them, too!&lt;/p&gt;</content><author><name></name></author><summary type="html">I recently launched two new Twitter bots! I guess, when Twitter bums me out for not meeting my quota of procedurally-generated silliness, I fill my feed with my own wacky creations. So, I’m glad to introduce @tsrewrite and @pussy_bot! These bots were both written with Python, use the Twython library to interact with Twitter’s API, and are running as cron jobs on PythonAnywhere’s cloud. Pussy Bot uses BeautifulSoup to parse an html document containing the text of the 1895 book Pussy and Her Language, by Marvin R. Clark. The program filters each sentence in the book by a tweetable length, and by some keywords that have to do with cats. This cuts down on the possible tweets quite a lot, as it is a verbose example of writing. I anticipate at one daily tweet that the bot will start to repeat itself obviously in about six months, at which point I will have to expand my filtering parameters, or add new Victorian literature about cats. Each sentence is accompanied by mid-to-late 19th century and early 20th century fine artworks featuring cats, mostly pulled from Wikimedia Commons. The src is here, if you are interested. My greatest desire is to interest the world in this worthy subject and induce investigations by others. pic.twitter.com/zPUSi3NMvb&amp;mdash; Victorian Cat Notes (@pussy_bot) August 12, 2017 Taylor Swift Rewrite rewrites the earwormiest Taylor Swift lyrics with NLTK. The scipt generating the tweets has three functions which plug in generated words in a mad-libs fashion. The script chooses words randomly by their part of speech from the Wordnet corpus. Some words are filtered by their common-ness by comparing them to the Webtext corpus; this cuts down on jargon words and proper nouns. At one point in the development of the script, it squashed all weird words, but I found I liked some of them. So it is not fully applied to every generated word. Another feature of the bot’s word picking is the ability to take a selected word and find a related word, ideally creating a pair. These pairs can be related by rhyme, using Allison Parrish’s excellent pronouncing library to find rhyming words. The pair can instead be related by meaning. I experimented with training my own models and using Word2Vec to use word vectors to find related words by meaning, but didn’t find the results accurate enough. So I have implemented the script with a pre-trained model from Google. The Google model’s results are much more accurate. Its thoroughness created a deployment issue, as my cloud solution will not tolerate a 1.5GB model running on it. For now, I run a local script once a month that generates the next month’s tweets, scan them with my human eyes :eyes: for anything potentially offensive, and upload the pickled file to the cloud. A script then accesses that file to tweet it through the month. The scripts powering the bot are here. She watches economic geography,I background crate,She&amp;#39;s topography,I have all this weight.&amp;mdash; Taylor Swift Rewrite (@tsrewrite) August 22, 2017 I’d like to experiment with other NLP stuff on this bot, and hopefully move it to a less-manual process. Training a model on Taylor Swift lyrics and implementing a Markov Chain sounds fun, and might do some of the work my script is doing implicitly - like filtering for “normal human song lyric”-quality words. I have previously made a Twitter bot using JSON and Kate Compton’s Tracery, and while it felt creative, it did not feel much like writing code or like a technical challenge. Tracery and Cheap Bots Done Quick are such excellent tools that they take care of a lot of the pain for you. I enjoyed digging a little deeper into the process, even though Twython also makes things fairly painless. It was terrific using my Python skills to get these bots working, and I’m looking forward to enjoying them in my feed. I hope you’ll follow and enjoy them, too!</summary></entry><entry><title type="html">A Retrospective Rewrite of Breakout in Python</title><link href="http://katieamazing.com/blog/2017/07/27/Breakout-All-The-Ways" rel="alternate" type="text/html" title="A Retrospective Rewrite of Breakout in Python" /><published>2017-07-27T00:00:00+00:00</published><updated>2017-07-27T00:00:00+00:00</updated><id>http://katieamazing.com/blog/2017/07/27/Breakout-All-The-Ways</id><content type="html" xml:base="http://katieamazing.com/blog/2017/07/27/Breakout-All-The-Ways">&lt;p&gt;Over a year ago, I wrote a version of &lt;a href=&quot;http://katieamazing.com/blog/2016/05/19/breakout-in-python&quot;&gt;Breakout in Python/CodeSkulptor&lt;/a&gt;. Since then, I’ve made versions of Breakout in different languages, and I thought it was time to revisit my old Python project.&lt;/p&gt;

&lt;p&gt;Gee, that code is ugly.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://media.giphy.com/media/d40ImzxOmRC0M/giphy.gif&quot; alt=&quot;cringe&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It’s time to rewrite this project, and show off how much I’ve grown in a year+ of programming. I spent some time experimenting with Python game frameworks, hoping to move my Python Breakout to a less-student-y game engine. I found PySDL2 really frustrating (SDL-related headaches are &lt;a href=&quot;http://katieamazing.com/blog/2017/07/03/C%C3%A9u-Game&quot;&gt;becoming a theme around here&lt;/a&gt;), so I rewrote the game in Pygame. Pygame was originally developed to replace PySDL(1), so I didn’t get that far away from SDL, but enough to make it an easier framework to deal with.&lt;/p&gt;

&lt;p&gt;So how’s my game look, a year later?&lt;/p&gt;

&lt;p&gt;In my original game, I made heavy use of global variables. Over 30 of them! It felt natural to do so as a newbie Pythonista, and my code is littered with imports from global space into my functions. Breakout 2.0 refactors everything into objects, so the global space is less crowded. You can see that I did use object orientation lightly early on, to handle the bubble particle effects. My improvement was to add a wrapping class, which functions as a container for individual particles. This divides the logic up between the wrapping class, which maintains a correct particle list and delegates control flow to each particle, and the particle class, which handles particle-level details like location, movement, and size of that particular particle.&lt;/p&gt;

&lt;p&gt;So I went from this tangle:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;particles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;                    &lt;span class=&quot;c1&quot;&gt;# A global container
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Particle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vel_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;randint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vel_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;randint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;randint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;alive&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vel_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vel_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vel_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vel_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vel_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vel_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vel_x&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vel_y&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HEIGHT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WIDTH&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;alive&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;canvas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;canvas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw_image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;img_bubble&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;make_particles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;numparticles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;randint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;things&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numparticles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;particles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Particle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;canvas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;particle&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;particles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;particle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;particle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;canvas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;particles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;particle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;particles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;particle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;alive&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;particles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Kill offscreen particles as a small optimization&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;To this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Particles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;particles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bubble&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;randint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)):&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;particles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Particle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;live_particles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bubble&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;particles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bubble&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;alive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;live_particles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bubble&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;bubble&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;particles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;live_particles&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bubble&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;particles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;bubble&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Particle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;velx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;randint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vely&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;randint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;randint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sprite&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pygame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;bubble15.png&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;alive&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;velx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;velx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;velx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;velx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vely&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vely&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;

        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;velx&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vely&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;alive&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sprite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pygame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We’ll see how Breakout 2.0’s bubbles get control flow to be drawn in a moment. I remember being so proud of 1.0’s Particle class; it was one of the first times I had used a class in Python, and getting particles working was satisfying. I’m even prouder of how much my use of classes has improved in the last year.&lt;/p&gt;

&lt;p&gt;One of the things I’ve gotten out of studying programming with experienced practitioners of the craft is a reluctance toward using inheritance. I am still prone to thinking in a UML-pattern that pushes my conception of objects as parents and children, but I have tried to resist the siren song (and the much-warned-of pitfalls) of inheritance. Breakout 2.0 uses polymorphism as a strategy to connect objects while avoiding classical inheritance.&lt;/p&gt;

&lt;p&gt;As we can see with the above code snippet of the Partical class, every drawable has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;draw()&lt;/code&gt; and an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update()&lt;/code&gt; method. Wrapping classes delegate down to individual objects (the particles and the bricks use the same strategy of a wrapping class around individual elements). The “hinge” of my polymorphism is an object that carries references to all the other objects, wiring them together. That way, the hinge object can iterate through every component it knows about, calling each component’s draw and update calls in turn.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Level&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cols&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bricksprite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rows&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rows&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cols&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cols&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bricksprite&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bricksprite&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;components&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;components&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;component&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;components&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;component&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;components&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;play&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ball&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Ball&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;collision_handler&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Collision&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ball&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;bubbles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Particles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;bricks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Bricks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cols&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bricksprite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collision_handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bubbles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;paddle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Paddle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;collision_handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;paddle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;collision_handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bricks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;paddle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ball&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bubbles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bricks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# ...
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;pygame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Level&lt;/code&gt; object also includes another bit of wiring to show off, which is the collision handler. This is an object which carries references to everything that might collide during the gameplay. As you can see, that is the ball, the paddle, and the bricks (the brick constructor handles adding each brick individually to the referenced collision handler). The collision handler prevents the ickiness of one object reaching out into another object’s data to check if they are colliding; the collision handler has the minimum amount of information required to determine a collision, delegates control flow to the concerned objects in the event of a collision, and also gets called on every loop as a component itself of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Level&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;Speaking of the ickiness of &lt;a href=&quot;http://wiki.c2.com/?InappropriateIntimacy&quot;&gt;inappropriate intimacy&lt;/a&gt;, one line in my new code really bothered me when I wrote it:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Brick&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sprite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collision_handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bubbles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# ...
&lt;/span&gt;        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bubbles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bubbles&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;on_collide&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bubbles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# TODO feels weird
&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The collision handler I described above delegates control flow to objects that have collided by calling the objects’ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;on_collide()&lt;/code&gt; methods (another small example of polymorphism in action). When a brick is collided, some brick stuff changes, and some bubble particles burst into existence. Having bricks know enough about enough to call the particle constructor feels really weird! For awhile during development, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bubbles&lt;/code&gt; object was global, so this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Brick on_collide()&lt;/code&gt; method was reaching into &lt;em&gt;global space&lt;/em&gt;! Argh. I went down a long and windy path of overengineering and implemented a publishing/subscription design, which is another wiring method where objects who will have messages (&lt;em&gt;“I’ve been hit!”&lt;/em&gt;) can publish those messages to subscribed functions (&lt;em&gt;“I, a bubble constructor, would like to know about bricks which have been hit,”&lt;/em&gt;). But it seemed like outrageous overkill for this small game. I eventually moved the bubbles wrapping class out of global space, and ended up passing the bubbles object into Brick as a constructor argument, which seems like a decent compromise.&lt;/p&gt;

&lt;p&gt;There are a couple other improvements that I can appreciate: my Python style is much better (&lt;a href=&quot;https://www.python.org/dev/peps/pep-0008/#a-foolish-consistency-is-the-hobgoblin-of-little-minds&quot;&gt;#hobgoblin&lt;/a&gt;), I have integrated the Pygame loop into my functions better, and overall I think this shows off my growth in using objects and designing a simple game.&lt;/p&gt;

&lt;p&gt;My first stab at this game in 2016 was highly practical. The heavy use of global variables made it fast to develop, but the largely monolithic design made it tough to update and it felt very fragile to work with. The new version swings way over to the other side, and is overengineered for such a small program - the LOC has grown, despite my omission of sounds and scoring in 2.0! But the code is much more extensible and the objects feel comfortable and natural to work with. You can find the full source code to Breakout 2.0 &lt;a href=&quot;https://github.com/katieamazing/breakout/blob/master/Snake-Flavored-pygame.py&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;BONUS ROUND:&lt;/em&gt; check out the same project I’ve written in &lt;a href=&quot;https://github.com/katieamazing/breakout/blob/master/Moon-Flavored.lua&quot;&gt;Lua&lt;/a&gt; and &lt;a href=&quot;https://github.com/katieamazing/breakout/blob/master/Tree-Flavored.elm&quot;&gt;Elm&lt;/a&gt;.&lt;/p&gt;</content><author><name></name></author><summary type="html">Over a year ago, I wrote a version of Breakout in Python/CodeSkulptor. Since then, I’ve made versions of Breakout in different languages, and I thought it was time to revisit my old Python project. Gee, that code is ugly. It’s time to rewrite this project, and show off how much I’ve grown in a year+ of programming. I spent some time experimenting with Python game frameworks, hoping to move my Python Breakout to a less-student-y game engine. I found PySDL2 really frustrating (SDL-related headaches are becoming a theme around here), so I rewrote the game in Pygame. Pygame was originally developed to replace PySDL(1), so I didn’t get that far away from SDL, but enough to make it an easier framework to deal with. So how’s my game look, a year later? In my original game, I made heavy use of global variables. Over 30 of them! It felt natural to do so as a newbie Pythonista, and my code is littered with imports from global space into my functions. Breakout 2.0 refactors everything into objects, so the global space is less crowded. You can see that I did use object orientation lightly early on, to handle the bubble particle effects. My improvement was to add a wrapping class, which functions as a container for individual particles. This divides the logic up between the wrapping class, which maintains a correct particle list and delegates control flow to each particle, and the particle class, which handles particle-level details like location, movement, and size of that particular particle. So I went from this tangle: particles = [] # A global container class Particle: def __init__(self, x, y): self.pos_x = x self.pos_y = y self.vel_y = random.randint(1, 4)*-1 self.vel_x = random.randint(-3,3)+.5 self.scale = random.randint(7,15) self.alive = True def update(self): if self.vel_x &amp;lt; 0: self.vel_x += 0.1 elif self.vel_x &amp;gt; 0: self.vel_x -= 0.1 if self.vel_y &amp;gt; 1: self.vel_y -= 0.1 self.pos_x += self.vel_x self.pos_y += self.vel_y if self.pos_y &amp;gt; HEIGHT +2 or self.pos_y &amp;lt; -1 or self.pos_x &amp;lt; -1 or self.pos_x &amp;gt; WIDTH +2: self.alive = False def draw(self, canvas): canvas.draw_image(img_bubble, (7,7), (15,15),(self.pos_x, self.pos_y), (self.scale, self.scale)) def make_particles(x, y): numparticles = random.randint(1,5) for things in range (0, numparticles): particles.append(Particle(x + 25, y + 13)) def draw(canvas): for particle in particles: particle.update() particle.draw(canvas) for i in range(len(particles)-1, 0, -1): particle = particles[i] if particle.alive == False: particles.pop(i) # Kill offscreen particles as a small optimization To this: class Particles(object): def __init__(self): self.particles = [] def create(self, x, y): for bubble in range(0, random.randint(1, 5)): self.particles.append(Particle(x + 25, y + 13)) def update(self): live_particles = [] for bubble in self.particles: if bubble.alive: live_particles.append(bubble) bubble.update() self.particles = live_particles def draw(self): for bubble in self.particles: bubble.draw() class Particle(object): def __init__(self, x, y): self.x = x self.y = y self.velx = (random.randint(-3, 3) + 0.5) / 2 self.vely = (random.randint(1, 4) * -1) / 5 self.scale = random.randint(7, 15) self.sprite = pygame.image.load(&quot;bubble15.png&quot;) self.alive = True def update(self): if self.velx &amp;lt; 0: self.velx += 0.1 elif self.velx &amp;gt; 0: self.velx -= 0.1 if self.vely &amp;gt; 1: self.vely -= 0.1 self.x += self.velx self.y += self.vely if self.y &amp;lt; - 1 or self.x &amp;lt; -1 or self.x &amp;gt; width + 2: self.alive = False def draw(self): screen.blit(self.sprite, pygame.Rect(self.x, self.y, self.scale, self.scale)) We’ll see how Breakout 2.0’s bubbles get control flow to be drawn in a moment. I remember being so proud of 1.0’s Particle class; it was one of the first times I had used a class in Python, and getting particles working was satisfying. I’m even prouder of how much my use of classes has improved in the last year. One of the things I’ve gotten out of studying programming with experienced practitioners of the craft is a reluctance toward using inheritance. I am still prone to thinking in a UML-pattern that pushes my conception of objects as parents and children, but I have tried to resist the siren song (and the much-warned-of pitfalls) of inheritance. Breakout 2.0 uses polymorphism as a strategy to connect objects while avoiding classical inheritance. As we can see with the above code snippet of the Partical class, every drawable has a draw() and an update() method. Wrapping classes delegate down to individual objects (the particles and the bricks use the same strategy of a wrapping class around individual elements). The “hinge” of my polymorphism is an object that carries references to all the other objects, wiring them together. That way, the hinge object can iterate through every component it knows about, calling each component’s draw and update calls in turn. class Level(object): def __init__(self, rows, cols, bricksprite): self.rows = rows self.cols = cols self.bricksprite = bricksprite self.components = [] def add(self, component): self.components.append(component) def update(self): for component in self.components: component.update() def draw(self): for component in self.components: component.draw() def play(self): ball = Ball(width/2, height-6) collision_handler = Collision(ball) bubbles = Particles() bricks = Bricks(self.rows, self.cols, self.bricksprite, collision_handler, bubbles) paddle = Paddle(width/2, 0) collision_handler.add(paddle) self.add(collision_handler) self.add(bricks) self.add(paddle) self.add(ball) self.add(bubbles) while not bricks.done(): # ... screen.blit(bg, (0,0)) self.update() self.draw() pygame.display.flip() The Level object also includes another bit of wiring to show off, which is the collision handler. This is an object which carries references to everything that might collide during the gameplay. As you can see, that is the ball, the paddle, and the bricks (the brick constructor handles adding each brick individually to the referenced collision handler). The collision handler prevents the ickiness of one object reaching out into another object’s data to check if they are colliding; the collision handler has the minimum amount of information required to determine a collision, delegates control flow to the concerned objects in the event of a collision, and also gets called on every loop as a component itself of the Level object. Speaking of the ickiness of inappropriate intimacy, one line in my new code really bothered me when I wrote it: class Brick(object): def __init__(self, x, y, sprite, collision_handler, bubbles): # ... self.bubbles = bubbles def on_collide(self): self.bubbles.create(self.x, self.y) # TODO feels weird # ... The collision handler I described above delegates control flow to objects that have collided by calling the objects’ on_collide() methods (another small example of polymorphism in action). When a brick is collided, some brick stuff changes, and some bubble particles burst into existence. Having bricks know enough about enough to call the particle constructor feels really weird! For awhile during development, the bubbles object was global, so this Brick on_collide() method was reaching into global space! Argh. I went down a long and windy path of overengineering and implemented a publishing/subscription design, which is another wiring method where objects who will have messages (“I’ve been hit!”) can publish those messages to subscribed functions (“I, a bubble constructor, would like to know about bricks which have been hit,”). But it seemed like outrageous overkill for this small game. I eventually moved the bubbles wrapping class out of global space, and ended up passing the bubbles object into Brick as a constructor argument, which seems like a decent compromise. There are a couple other improvements that I can appreciate: my Python style is much better (#hobgoblin), I have integrated the Pygame loop into my functions better, and overall I think this shows off my growth in using objects and designing a simple game. My first stab at this game in 2016 was highly practical. The heavy use of global variables made it fast to develop, but the largely monolithic design made it tough to update and it felt very fragile to work with. The new version swings way over to the other side, and is overengineered for such a small program - the LOC has grown, despite my omission of sounds and scoring in 2.0! But the code is much more extensible and the objects feel comfortable and natural to work with. You can find the full source code to Breakout 2.0 here. BONUS ROUND: check out the same project I’ve written in Lua and Elm.</summary></entry><entry><title type="html">Being a Programming Language Hipster with Céu</title><link href="http://katieamazing.com/blog/2017/07/03/C%C3%A9u-Game" rel="alternate" type="text/html" title="Being a Programming Language Hipster with Céu" /><published>2017-07-03T00:00:00+00:00</published><updated>2017-07-03T00:00:00+00:00</updated><id>http://katieamazing.com/blog/2017/07/03/C%C3%A9u-Game</id><content type="html" xml:base="http://katieamazing.com/blog/2017/07/03/C%C3%A9u-Game">&lt;p&gt;I did a little game project recently in a new-to-me language. You’ve probably never heard of it.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i0.kym-cdn.com/photos/images/newsfeed/000/145/704/tumblr_lnzjlg3IK71qjwu4eo1_500.jpg&quot; alt=&quot;Hipster doggo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It’s called &lt;a href=&quot;http://ceu-lang.org/&quot;&gt;Céu&lt;/a&gt;. The SDL bindings I used were added to the language super-recently. I wanted to try working in Céu as I’ve been learning about concurrency in Python, and making something in a language that is all about synchronous design and concurrency appealed to me. So it was an interesting and challenging experience to make a game in a couple days with these tools:&lt;/p&gt;

&lt;p&gt;Céu is a young language, and there is sparse to &lt;strong&gt;no documentation&lt;/strong&gt; for the SDL environment. There is a nice manual available online, and some academic papers. But both of those have to do with the Céu language more generally.&lt;/p&gt;

&lt;p&gt;Error messages in Céu are &lt;strong&gt;not Googleable&lt;/strong&gt;. You are not going to be able to find many helpful answers for issues that come up in Céu development on StackOverflow. There is a Google Group where Céu is discussed, the documentation mentioned above, and a Gitter chat group, but getting an immediate solution to a specific problem is tough using the usual tried and true method of a quick search.&lt;/p&gt;

&lt;p&gt;Another error-related feature I take for granted is that the console error message will help me locate and track down bugs as I develop. But Céu has &lt;strong&gt;unhelpful console error messages&lt;/strong&gt;. Console error messages provide a line number in Céu, but it is a wild goose chase. I am speculating, but I think the line number refers to compiled code. So it’s not much help in tracking down bugs, especially small syntactic errors like missing semicolons and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;end&lt;/code&gt;. It’s not entirely pointless, as errors do at least tell you &lt;em&gt;what&lt;/em&gt; issue you are looking for, if not &lt;em&gt;where&lt;/em&gt; to find it.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/katieamazing/katieamazing.github.io/master/img/errormess3.jpg&quot; alt=&quot;unhelpful error messages&quot; /&gt;&lt;/p&gt;

&lt;p&gt;On the plus side, there were twelve example programs that shipped with the SDL environment for Céu. Those were what I referenced whenever I wanted to get something accomplished. Still, there were some really hard problems - getting a string variable that would be updated with the score turned out to be a huge problem. After trying to get it working for a few hours (!), I worked around the issue of having a text variable rendered to screen with a graphical score display.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/katieamazing/katieamazing.github.io/master/img/score.gif&quot; alt=&quot;graphical score display&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A lot of the language’s features were new to me. Such as:&lt;/p&gt;

&lt;p&gt;This is what &lt;strong&gt;a helper function&lt;/strong&gt; looks like in Céu:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// A simple rect-rect collision checking function
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tight&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Collision&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SDL_Rect&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SDL_Rect&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bool&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;escape&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;escape&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;escape&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;escape&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;escape&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And here’s what &lt;strong&gt;a class&lt;/strong&gt; looks like:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Particle&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_SDL_Renderer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ren&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SDL_Rect&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ship_velx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ship_vely&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SDL_Color&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// Generate particles with randomized velocity that take into account the ship's velocity on impact
&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;velx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_rand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ship_velx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vely&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_rand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ship_vely&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;par&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Shrink the particles every quarter-second
&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;every&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;250&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ms&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;then&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;with&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Check that the particle is still on-screen and move it
&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// If offscreen, break the whole execution for this particle
&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;every&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ms&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;800&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;480&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;then&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;velx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vely&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;with&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Draw the particle
&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;every&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SDL_REDRAW&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;nf&quot;&gt;_SDL_SetRenderDrawColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ren&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;_SDL_RenderFillRect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ren&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_SDL_Rect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The main feature of Céu is trails of execution, which are marked by blocks starting with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;par&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;par/and&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;par/or&lt;/code&gt;, and connected blocks starting with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;with&lt;/code&gt;. These trails execute in parallel, and allow the program to model simultaneous threads of logic waiting for multiple events. The &lt;a href=&quot;http://fsantanna.github.io/ceu/out/manual/v0.20/#parallel-compositions-and-abortion&quot;&gt;three different parallel block keywords&lt;/a&gt; indicate different behavior when one of the blocks terminates, which you can see above in the Particle class example.&lt;/p&gt;

&lt;p&gt;Céu provides parallel compositions to allow multiple lines of execution, aka trails, to coexist and wait for multiple events. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; is available to suspend a trail and wait for an event from the outer environment that Céu is running it, and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;emit&lt;/code&gt; statement signals an output event back to the environment. Parallel compositions allow the code to wait for and react to multiple events from the environment and from the program itself really fast.&lt;/p&gt;

&lt;p&gt;My finished program has some &lt;strong&gt;errors&lt;/strong&gt; at compile time. The late frame warnings are because my antivirus is quite defensive about these programs, so nothing troubling there. But Céu warns me that I have &lt;em&gt;tight loops&lt;/em&gt;, or unbounded loops.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/katieamazing/katieamazing.github.io/master/img/errormess2.gif&quot; alt=&quot;Compile time errors&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Céu wants each path inside the body of a loop to contain at least one &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;break&lt;/code&gt; statement. This is to ensure that reaction chains never run in an arbitrary amount of time.&lt;/p&gt;

&lt;p&gt;The compiler detects and warns when trails can run in unbounded time: loops that do not await or break, the so-called tight loops.&lt;/p&gt;

&lt;p&gt;One way to rewrite the tight loops which Céu is warning me about would be Ceu’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await async (variable) do&lt;/code&gt;. But the warnings do not negatively impact this small program, so it’s more of an imperative-programmer style incompatibility issue here. Something to overcome next time!&lt;/p&gt;

&lt;p&gt;Overall, I really enjoyed working with Céu, and was proud of the end result in proportion to how difficult it was to develop without some of my usual toolkit. I particularly like how the language pushes the developer toward object-oriented design. I could easily see becoming a Céu evangelist; it is an amazing project, and the more I learn the more impressed I am. I’m looking forward to doing more with Céu soon!&lt;/p&gt;

&lt;p&gt;The game itself isn’t super interesting, but there’s a gif of gameplay below. The source code is in &lt;a href=&quot;https://github.com/katieamazing/rc_game_ceu&quot;&gt;this repo&lt;/a&gt;, and if you have a Windows environment, you can download the complied code there and play the game.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/katieamazing/katieamazing.github.io/master/img/ceu-game.gif&quot; alt=&quot;Gameplay gif&quot; /&gt;&lt;/p&gt;</content><author><name></name></author><summary type="html">I did a little game project recently in a new-to-me language. You’ve probably never heard of it. It’s called Céu. The SDL bindings I used were added to the language super-recently. I wanted to try working in Céu as I’ve been learning about concurrency in Python, and making something in a language that is all about synchronous design and concurrency appealed to me. So it was an interesting and challenging experience to make a game in a couple days with these tools: Céu is a young language, and there is sparse to no documentation for the SDL environment. There is a nice manual available online, and some academic papers. But both of those have to do with the Céu language more generally. Error messages in Céu are not Googleable. You are not going to be able to find many helpful answers for issues that come up in Céu development on StackOverflow. There is a Google Group where Céu is discussed, the documentation mentioned above, and a Gitter chat group, but getting an immediate solution to a specific problem is tough using the usual tried and true method of a quick search. Another error-related feature I take for granted is that the console error message will help me locate and track down bugs as I develop. But Céu has unhelpful console error messages. Console error messages provide a line number in Céu, but it is a wild goose chase. I am speculating, but I think the line number refers to compiled code. So it’s not much help in tracking down bugs, especially small syntactic errors like missing semicolons and end. It’s not entirely pointless, as errors do at least tell you what issue you are looking for, if not where to find it. On the plus side, there were twelve example programs that shipped with the SDL environment for Céu. Those were what I referenced whenever I wanted to get something accomplished. Still, there were some really hard problems - getting a string variable that would be updated with the score turned out to be a huge problem. After trying to get it working for a few hours (!), I worked around the issue of having a text variable rendered to screen with a graphical score display. A lot of the language’s features were new to me. Such as: This is what a helper function looks like in Céu: // A simple rect-rect collision checking function code/tight Collision (var SDL_Rect r1, var SDL_Rect r2) -&amp;gt; bool do if r1.x+r1.w &amp;lt; r2.x then escape false; end if r1.y+r1.h &amp;lt; r2.y then escape false; end if r2.x+r2.w &amp;lt; r1.x then escape false; end if r2.y+ r2.h &amp;lt; r1.y then escape false; end escape true; end And here’s what a class looks like: code/await Particle (var&amp;amp; _SDL_Renderer ren, var SDL_Rect rect, var int ship_velx, var int ship_vely, var SDL_Color c) -&amp;gt; void do // Generate particles with randomized velocity that take into account the ship's velocity on impact var int velx = _rand() % 6 - 3 + ship_velx; var int vely = _rand() % 6 - 3 + ship_vely; par/or do // Shrink the particles every quarter-second every 250ms do if rect.w &amp;gt; 1 then rect.w = rect.w - 1; rect.h = rect.h - 1; else break; end end with // Check that the particle is still on-screen and move it // If offscreen, break the whole execution for this particle every 50ms do if rect.x &amp;gt; 0 and rect.x &amp;lt; 800 and rect.y &amp;gt; 0 and rect.y &amp;lt; 480 then rect.x = rect.x + velx; rect.y = rect.y + vely; else break; end end with // Draw the particle every SDL_REDRAW do _SDL_SetRenderDrawColor(&amp;amp;&amp;amp;ren, c.r, c.g, c.b, c.a); _SDL_RenderFillRect(&amp;amp;&amp;amp;ren, (&amp;amp;&amp;amp;rect as _SDL_Rect&amp;amp;&amp;amp;)); end end end The main feature of Céu is trails of execution, which are marked by blocks starting with par, par/and, par/or, and connected blocks starting with with. These trails execute in parallel, and allow the program to model simultaneous threads of logic waiting for multiple events. The three different parallel block keywords indicate different behavior when one of the blocks terminates, which you can see above in the Particle class example. Céu provides parallel compositions to allow multiple lines of execution, aka trails, to coexist and wait for multiple events. The await is available to suspend a trail and wait for an event from the outer environment that Céu is running it, and the emit statement signals an output event back to the environment. Parallel compositions allow the code to wait for and react to multiple events from the environment and from the program itself really fast. My finished program has some errors at compile time. The late frame warnings are because my antivirus is quite defensive about these programs, so nothing troubling there. But Céu warns me that I have tight loops, or unbounded loops. Céu wants each path inside the body of a loop to contain at least one await or break statement. This is to ensure that reaction chains never run in an arbitrary amount of time. The compiler detects and warns when trails can run in unbounded time: loops that do not await or break, the so-called tight loops. One way to rewrite the tight loops which Céu is warning me about would be Ceu’s await async (variable) do. But the warnings do not negatively impact this small program, so it’s more of an imperative-programmer style incompatibility issue here. Something to overcome next time! Overall, I really enjoyed working with Céu, and was proud of the end result in proportion to how difficult it was to develop without some of my usual toolkit. I particularly like how the language pushes the developer toward object-oriented design. I could easily see becoming a Céu evangelist; it is an amazing project, and the more I learn the more impressed I am. I’m looking forward to doing more with Céu soon! The game itself isn’t super interesting, but there’s a gif of gameplay below. The source code is in this repo, and if you have a Windows environment, you can download the complied code there and play the game.</summary></entry><entry><title type="html">Recurse Center: Days[74:]</title><link href="http://katieamazing.com/blog/2017/06/29/RCDays74-end" rel="alternate" type="text/html" title="Recurse Center: Days[74:]" /><published>2017-06-29T00:00:00+00:00</published><updated>2017-06-29T00:00:00+00:00</updated><id>http://katieamazing.com/blog/2017/06/29/RCDays74-end</id><content type="html" xml:base="http://katieamazing.com/blog/2017/06/29/RCDays74-end">&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/katieamazing/katieamazing.github.io/master/img/rc-2017.jpg&quot; alt=&quot;It really is all about the people.&quot; /&gt;&lt;/p&gt;</content><author><name></name></author><summary type="html"></summary></entry><entry><title type="html">Recurse Center: Days[39:74]</title><link href="http://katieamazing.com/blog/2017/06/12/RCDays39-74" rel="alternate" type="text/html" title="Recurse Center: Days[39:74]" /><published>2017-06-12T00:00:00+00:00</published><updated>2017-06-12T00:00:00+00:00</updated><id>http://katieamazing.com/blog/2017/06/12/RCDays39-74</id><content type="html" xml:base="http://katieamazing.com/blog/2017/06/12/RCDays39-74">&lt;p&gt;A long time has passed since updating this blog with my RC-doings!&lt;/p&gt;

&lt;p&gt;There was a two week break in May, during which RC was not in session. I chose to skip the Never Graduate week reunion, which occurred over the first week of the break. The second week was mostly occupied with PyCon. I traveled to Oregon to attend my first PyCon, and it was a wonderful experience. Over the break, I got a lot less done than I wanted to. But I wrapped up a few things, and started some new ones. !!Con at the start of the break and PyCon at the end were amazing, and were where I spent a lot of my social energy.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/katieamazing/katieamazing.github.io/master/img/IMG-20170521-WA0007.jpg&quot; alt=&quot;PyCon with friends new and old&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I ran a second Refucktoring event during the last three weeks, and am prepping for another this week. I provide small programs from reputable sources, with test suites, and the participants pair up and practice redder/greener refactoring to produce very bad code which still passes the tests. I wanted to add JavaScript, Lua, and C programs to the available projects. There are a lot of options for testing frameworks, but I chose Jasmine for JavaScript testing. I also did a bit of testing with the Lua Busted framework for a Lua program. Overall, Refucktoring has been a fun and satisfying project to prepare and run, and it has let me explore &lt;strong&gt;testing frameworks in multiple languages&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I watched a couple videos about &lt;strong&gt;concurrency&lt;/strong&gt; in Python that got me interested in the subject, and I have to admit I’ve fallen down a bit of a rabbit hole! I’ve done a bit of passive learning about concurrency and async/await topics in Python, but my interest quickly split off into the Céu game I made as part of the recent game jam.&lt;/p&gt;

&lt;p&gt;Oh right, the &lt;strong&gt;game jam&lt;/strong&gt;! I organized a RC Sprummer (Spring + Summer) Game Jam over the last week/weekend! I modeled it on my Ludum Dare experiences, and hoped people would invest about two days making a game. People seemed to enjoy it, and made very impressive and interesting games. For Recursers, you can see all the games made on the &lt;a href=&quot;https://github.com/recursecenter/wiki/wiki/Game-Jam&quot;&gt;wiki page for Game Jams&lt;/a&gt;. My own game is detailed &lt;a href=&quot;http://katieamazing.com/blog/2017/07/03/C%C3%A9u-Game&quot;&gt;here&lt;/a&gt;. I had played around with the Python SDL2 stuff earlier last week before committing to working with &lt;strong&gt;&lt;a href=&quot;http://ceu-lang.org/&quot;&gt;Céu’s&lt;/a&gt; brand new SDL bindings&lt;/strong&gt;. It was challenging and fun to work with such young technology.&lt;/p&gt;

&lt;p&gt;I tried to build some enthusiasm for the Game Jam was giving a quick presentation on the first day of the new batch. I have been nervous to do &lt;strong&gt;public speaking about code&lt;/strong&gt;. I wanted to speak the first day because I remember my first day at RC concluding with some intimidating presentations by people in the former batch, and a few people in my batch, too! It made me anxious and created a lot of extra impostor syndrome. I hoped that by talking about something light in a casual way, that I’d bring some levity and set the bar at a more reasonable place for the new batch. Overcoming my technical public speaking fears is not something I’ve focused on heavily at RC, but it felt good to succeed, even at a very brief and fun talk.&lt;/p&gt;

&lt;p&gt;My &lt;strong&gt;book a week&lt;/strong&gt; project was stalled the last few weeks. I’ve been busy reading, but “Fluent Python” by Luciano Ramalho has been long to get through. I’m finished now, though, and excited to get back on schedule. I got a lot out of the book, and look forward to it being a resource for a long time to come. I had a really great experience meeting the author, Luciano at PyCon, in fact. I mentioned I was reading the book, and he asked me how I was liking it. I was honest and said, “It is great, but long!” He was very sweet about it, and said if he was to do it all again, he might consider releasing the book as a series of 5 or 6 books. So by the author’s own count, I am more or less on schedule for a book a week! I also read some of “Pearls of Functional Algorithm Design” by Richard Bird, but abandoned it halfway. I might return to it when I am willing to invest more time per chapter, trying to implement the algorithmic coolness in Python.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/katieamazing/katieamazing.github.io/master/img/IMG_20170606_134900907_TOP.jpg&quot; alt=&quot;Weekend setup including some programming books and lots of index card notes&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I’ve had a hard time adjusting back to RC life following the break. The demographics of the new batch make me pretty uncomfortable; RC is now about 20-25% female. The vibe has changed along with that, and is now more study-hall and less summer-camp. I miss the freewheeling social life and collaborative, safe environment that seems much diminished now, and the slightly competitive atmosphere is hard to manage for me. I’m hoping I can recover and make good friends with some of the new people, or at least find a way to put my head down and get lots of work done. Running lots of events and leaning on the staff and my friends has helped a bit.&lt;/p&gt;</content><author><name></name></author><summary type="html">A long time has passed since updating this blog with my RC-doings! There was a two week break in May, during which RC was not in session. I chose to skip the Never Graduate week reunion, which occurred over the first week of the break. The second week was mostly occupied with PyCon. I traveled to Oregon to attend my first PyCon, and it was a wonderful experience. Over the break, I got a lot less done than I wanted to. But I wrapped up a few things, and started some new ones. !!Con at the start of the break and PyCon at the end were amazing, and were where I spent a lot of my social energy. I ran a second Refucktoring event during the last three weeks, and am prepping for another this week. I provide small programs from reputable sources, with test suites, and the participants pair up and practice redder/greener refactoring to produce very bad code which still passes the tests. I wanted to add JavaScript, Lua, and C programs to the available projects. There are a lot of options for testing frameworks, but I chose Jasmine for JavaScript testing. I also did a bit of testing with the Lua Busted framework for a Lua program. Overall, Refucktoring has been a fun and satisfying project to prepare and run, and it has let me explore testing frameworks in multiple languages. I watched a couple videos about concurrency in Python that got me interested in the subject, and I have to admit I’ve fallen down a bit of a rabbit hole! I’ve done a bit of passive learning about concurrency and async/await topics in Python, but my interest quickly split off into the Céu game I made as part of the recent game jam. Oh right, the game jam! I organized a RC Sprummer (Spring + Summer) Game Jam over the last week/weekend! I modeled it on my Ludum Dare experiences, and hoped people would invest about two days making a game. People seemed to enjoy it, and made very impressive and interesting games. For Recursers, you can see all the games made on the wiki page for Game Jams. My own game is detailed here. I had played around with the Python SDL2 stuff earlier last week before committing to working with Céu’s brand new SDL bindings. It was challenging and fun to work with such young technology. I tried to build some enthusiasm for the Game Jam was giving a quick presentation on the first day of the new batch. I have been nervous to do public speaking about code. I wanted to speak the first day because I remember my first day at RC concluding with some intimidating presentations by people in the former batch, and a few people in my batch, too! It made me anxious and created a lot of extra impostor syndrome. I hoped that by talking about something light in a casual way, that I’d bring some levity and set the bar at a more reasonable place for the new batch. Overcoming my technical public speaking fears is not something I’ve focused on heavily at RC, but it felt good to succeed, even at a very brief and fun talk. My book a week project was stalled the last few weeks. I’ve been busy reading, but “Fluent Python” by Luciano Ramalho has been long to get through. I’m finished now, though, and excited to get back on schedule. I got a lot out of the book, and look forward to it being a resource for a long time to come. I had a really great experience meeting the author, Luciano at PyCon, in fact. I mentioned I was reading the book, and he asked me how I was liking it. I was honest and said, “It is great, but long!” He was very sweet about it, and said if he was to do it all again, he might consider releasing the book as a series of 5 or 6 books. So by the author’s own count, I am more or less on schedule for a book a week! I also read some of “Pearls of Functional Algorithm Design” by Richard Bird, but abandoned it halfway. I might return to it when I am willing to invest more time per chapter, trying to implement the algorithmic coolness in Python. I’ve had a hard time adjusting back to RC life following the break. The demographics of the new batch make me pretty uncomfortable; RC is now about 20-25% female. The vibe has changed along with that, and is now more study-hall and less summer-camp. I miss the freewheeling social life and collaborative, safe environment that seems much diminished now, and the slightly competitive atmosphere is hard to manage for me. I’m hoping I can recover and make good friends with some of the new people, or at least find a way to put my head down and get lots of work done. Running lots of events and leaning on the staff and my friends has helped a bit.</summary></entry><entry><title type="html">Recurse Center: Days[19:39]</title><link href="http://katieamazing.com/blog/2017/05/17/RCDays19-39" rel="alternate" type="text/html" title="Recurse Center: Days[19:39]" /><published>2017-05-17T00:00:00+00:00</published><updated>2017-05-17T00:00:00+00:00</updated><id>http://katieamazing.com/blog/2017/05/17/RCDays19-39</id><content type="html" xml:base="http://katieamazing.com/blog/2017/05/17/RCDays19-39">&lt;p&gt;Three more weeks down! Time is absolutely speeding. What have I been up to over the last three weeks?&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://katieamazing.com/blog/2017/04/25/LD38&quot;&gt;&lt;img src=&quot;https://raw.githubusercontent.com/katieamazing/katieamazing.github.io/master/games/LD38/mixed.jpg&quot; alt=&quot;LD38 Game: Whirled of Words&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’ve been working on some programming stuff that is not strictly tied to RC this week, but they all bleed into one another. &lt;strong&gt;Ludum Dare 38&lt;/strong&gt; was the weekend of April 22nd, and I did the jam competition. My partner and I made a simple game described &lt;a href=&quot;http://katieamazing.com/blog/2017/04/25/LD38&quot;&gt;here&lt;/a&gt; in more detail. I showed it off at RC the following week, which was gratifying. Unfortunately, I didn’t manage to Pied-Piper any other Recursers into doing Ludum Dare with me (some did, but as far as I know, no one in batch). That was mostly due to…&lt;/p&gt;

&lt;p&gt;Conference-going has really picked up this spring! The inaugural &lt;strong&gt;Codeland&lt;/strong&gt; coincided with most of the Ludum Dare weekend (it was all day Friday-Saturday, which really cramped my LD-style). It was a very worthwhile event, though. And then &lt;strong&gt;!!Con 2017&lt;/strong&gt; was two weeks later, and predictably fabulous. Both conferences were really social and inspiring. They also gave me an opportunity to benchmark my progress; Codeland is a conference for “code newbies”, and my experience was a little bittersweet as I realized I am not a newbie any more. And my experience at !!Con was super different than last year - I followed technical aspects of talks better, felt less mind-blown all the time (or at least, the mind-blowing had an “OMG COOL” feel rather than an “OMG I am so lost” feel), and I was more confident introducing myself to strangers as a programmer.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/katieamazing/katieamazing.github.io/master/img/codeland-nyc.jpg&quot; alt=&quot;speaker Opher and I at Codeland, photo credit McBilly Sy&quot; /&gt;&lt;/p&gt;

&lt;p&gt;One neat thing that Codeland included was a workshop morning, and I chose to attend a &lt;strong&gt;Docker&lt;/strong&gt; containerization workshop. It was hosted by some guys from a sponsoring organization, Linode, so we got to deploy Flask, Django, and Wordpress “hello world” apps to already-spun-up linodes in the cloud. That was pretty neat, and I learned a lot about containerization and what that actually is. That background dovetailed nicely into a talk that the fantastic &lt;a href=&quot;https://github.com/botwhytho&quot;&gt;@botwhytho&lt;/a&gt; gave at RC at the end of last week about containerization. He covered a little more about Docker, talked about other containerization technologies like Kubernetes, and presented without the lens of Linode. So that was an educational tie-in.&lt;/p&gt;

&lt;p&gt;And it was nice to be talking about deploying &lt;strong&gt;Flask and Django&lt;/strong&gt; apps to containers while I was working on getting a better handle on those frameworks. RC held a Flaskapalooza day a week or two ago, and it was the first engagement I had had with Flask. It has inspired me to start a small project in Flask. And the incredibly patient &lt;a href=&quot;https://github.com/ivanistheone&quot;&gt;@ivanistheone&lt;/a&gt; walked me through a Django 101 last week, where we built a beginner Django project up from scratch. Despite using Django for a few months now for a web game project I am working on, I feel super shaky on Django (in large part because I am ignoring all good advice and trying to learn Django and Elm concurrently). It was great to get a walkthrough from someone who is an expert, and a really efficient and pleasant way to get more knowledge about how Django actually works. My confidence as I get back to working on my existing project is much higher!&lt;/p&gt;

&lt;p&gt;I let &lt;strong&gt;interview prep&lt;/strong&gt; work take a back seat over these weeks, having noticed how much of a negative impact it was having on my mood. I also met and talked with others from RC who came from nontechnical backgrounds and focused on Python, and they had pretty long job hunts ranging from 3 to 6 months (:scream:). The realization that my job hunt after RC is likely to be long has me reconsidering my plan to spend the last half of my batch focused on job-hunting activities. Even so, I’ve been keeping up with exercism.io programming exercises (I got to meet founder Katrina Owen at Codeland Conference, that was AMAZING!), I attended the Women Who Code NYC monthly algorithm meetup, and I did one session of whiteboarding practice and planned more for the next 6 weeks.&lt;/p&gt;

&lt;p&gt;My biggest win over these three weeks was submitting &lt;strong&gt;my first PR&lt;/strong&gt; to an open source project. &lt;strong&gt;Open source contribution&lt;/strong&gt; was a goal I had for my time at RC, and it took multiple tries pairing with the wildly wonderful &lt;a href=&quot;https://github.com/eliasdorneles/&quot;&gt;@eliasdorneles&lt;/a&gt; to get onboarded onto the &lt;a href=&quot;https://github.com/pybee/voc&quot;&gt;PyBeeWare VOC transpiler&lt;/a&gt; project sufficiently to submit my (very first ever!) PR. A few tweaks later and it was merged, and that feels awesome. The community of that project was so supportive and excited on Github and Twitter, and that was the cherry on top! I’m excited to try and do another PR without the training wheels of an experienced contributor over my shoulder.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/katieamazing/katieamazing.github.io/master/img/Untitled-3.jpg&quot; alt=&quot;I am not Twitter popular, this was a Big Deal for me&quot; /&gt;&lt;/p&gt;

&lt;p&gt;My ambitious &lt;strong&gt;a book a week&lt;/strong&gt; during RC project has ground to a halt. I started reading “Fluent Python” by Luciano Ramalho after my first three books, and it has been slow. It is valuable, but dense and not at all conversational or skimmable. I will continue reading over the two week break and resolve to put it aside when RC resumes so I can get back to my schedule.&lt;/p&gt;

&lt;p&gt;At the end of last week, my friends from the overlapping Spring 1 left. Before they went, I had blocked off the whole week to be social and soak up as much of those beloved people as I could, which I really enjoyed. Though it definitely was a hit to my productivity, being super sociable and staying out late most nights was wonderful. I hope I can find a way to add more of that into my next weeks at RC. If I want to keep my programming productivity up, my home-life tasks will be the ones to suffer. But I think I can let that slide for six weeks without too big a penalty (hopefully not famous last words!).&lt;/p&gt;

&lt;p&gt;So, it was hard to say goodbye, but it has reminded me to enjoy the RC ride to the fullest. I know it will be over so soon, and I have to do my best to make the most of it and cherish the people AND the work!&lt;/p&gt;

&lt;p&gt;Next comes two weeks “off” (my todo list is silly-long), and then three more weeks!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://media.giphy.com/media/VKO54bedbJ0uk/giphy.gif&quot; alt=&quot;Let's rock this bitch.&quot; /&gt;&lt;/p&gt;</content><author><name></name></author><summary type="html">Three more weeks down! Time is absolutely speeding. What have I been up to over the last three weeks? I’ve been working on some programming stuff that is not strictly tied to RC this week, but they all bleed into one another. Ludum Dare 38 was the weekend of April 22nd, and I did the jam competition. My partner and I made a simple game described here in more detail. I showed it off at RC the following week, which was gratifying. Unfortunately, I didn’t manage to Pied-Piper any other Recursers into doing Ludum Dare with me (some did, but as far as I know, no one in batch). That was mostly due to… Conference-going has really picked up this spring! The inaugural Codeland coincided with most of the Ludum Dare weekend (it was all day Friday-Saturday, which really cramped my LD-style). It was a very worthwhile event, though. And then !!Con 2017 was two weeks later, and predictably fabulous. Both conferences were really social and inspiring. They also gave me an opportunity to benchmark my progress; Codeland is a conference for “code newbies”, and my experience was a little bittersweet as I realized I am not a newbie any more. And my experience at !!Con was super different than last year - I followed technical aspects of talks better, felt less mind-blown all the time (or at least, the mind-blowing had an “OMG COOL” feel rather than an “OMG I am so lost” feel), and I was more confident introducing myself to strangers as a programmer. One neat thing that Codeland included was a workshop morning, and I chose to attend a Docker containerization workshop. It was hosted by some guys from a sponsoring organization, Linode, so we got to deploy Flask, Django, and Wordpress “hello world” apps to already-spun-up linodes in the cloud. That was pretty neat, and I learned a lot about containerization and what that actually is. That background dovetailed nicely into a talk that the fantastic @botwhytho gave at RC at the end of last week about containerization. He covered a little more about Docker, talked about other containerization technologies like Kubernetes, and presented without the lens of Linode. So that was an educational tie-in. And it was nice to be talking about deploying Flask and Django apps to containers while I was working on getting a better handle on those frameworks. RC held a Flaskapalooza day a week or two ago, and it was the first engagement I had had with Flask. It has inspired me to start a small project in Flask. And the incredibly patient @ivanistheone walked me through a Django 101 last week, where we built a beginner Django project up from scratch. Despite using Django for a few months now for a web game project I am working on, I feel super shaky on Django (in large part because I am ignoring all good advice and trying to learn Django and Elm concurrently). It was great to get a walkthrough from someone who is an expert, and a really efficient and pleasant way to get more knowledge about how Django actually works. My confidence as I get back to working on my existing project is much higher! I let interview prep work take a back seat over these weeks, having noticed how much of a negative impact it was having on my mood. I also met and talked with others from RC who came from nontechnical backgrounds and focused on Python, and they had pretty long job hunts ranging from 3 to 6 months (:scream:). The realization that my job hunt after RC is likely to be long has me reconsidering my plan to spend the last half of my batch focused on job-hunting activities. Even so, I’ve been keeping up with exercism.io programming exercises (I got to meet founder Katrina Owen at Codeland Conference, that was AMAZING!), I attended the Women Who Code NYC monthly algorithm meetup, and I did one session of whiteboarding practice and planned more for the next 6 weeks. My biggest win over these three weeks was submitting my first PR to an open source project. Open source contribution was a goal I had for my time at RC, and it took multiple tries pairing with the wildly wonderful @eliasdorneles to get onboarded onto the PyBeeWare VOC transpiler project sufficiently to submit my (very first ever!) PR. A few tweaks later and it was merged, and that feels awesome. The community of that project was so supportive and excited on Github and Twitter, and that was the cherry on top! I’m excited to try and do another PR without the training wheels of an experienced contributor over my shoulder. My ambitious a book a week during RC project has ground to a halt. I started reading “Fluent Python” by Luciano Ramalho after my first three books, and it has been slow. It is valuable, but dense and not at all conversational or skimmable. I will continue reading over the two week break and resolve to put it aside when RC resumes so I can get back to my schedule. At the end of last week, my friends from the overlapping Spring 1 left. Before they went, I had blocked off the whole week to be social and soak up as much of those beloved people as I could, which I really enjoyed. Though it definitely was a hit to my productivity, being super sociable and staying out late most nights was wonderful. I hope I can find a way to add more of that into my next weeks at RC. If I want to keep my programming productivity up, my home-life tasks will be the ones to suffer. But I think I can let that slide for six weeks without too big a penalty (hopefully not famous last words!). So, it was hard to say goodbye, but it has reminded me to enjoy the RC ride to the fullest. I know it will be over so soon, and I have to do my best to make the most of it and cherish the people AND the work! Next comes two weeks “off” (my todo list is silly-long), and then three more weeks!</summary></entry><entry><title type="html">I Coded in Python for a Year Without Knowing These Ten Things</title><link href="http://katieamazing.com/blog/2017/05/13/Python-Goodies" rel="alternate" type="text/html" title="I Coded in Python for a Year Without Knowing These Ten Things" /><published>2017-05-13T00:00:00+00:00</published><updated>2017-05-13T00:00:00+00:00</updated><id>http://katieamazing.com/blog/2017/05/13/Python-Goodies</id><content type="html" xml:base="http://katieamazing.com/blog/2017/05/13/Python-Goodies">&lt;p&gt;Forgive me for my clickbait title.&lt;/p&gt;

&lt;p&gt;It’s been a little over a year since I first started learning Python! In the last few months, I have deepened my knowledge of the language considerably, and I’ve discovered some startling gaps. This is the blog post I wish I had read earlier in my Python education, and I hope you find it useful (or maybe just amusing? :flushed:)&lt;/p&gt;

&lt;body&gt;
&lt;hr /&gt;
&lt;/body&gt;

&lt;p&gt;&lt;strong&gt;1. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;in&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now, I was familiar with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;in&lt;/code&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for&lt;/code&gt; loops! But using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;in&lt;/code&gt; alone as a test for membership had not occurred to me in my first year of Python programming. If we have a collection (like a list or a string) and we’d like to see if that collection contains a value or not, we can use:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;classes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'English'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'Math'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'Science'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'Math'&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;classes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'Yay, Math!'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'History'&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;classes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'Doomed to repeat our mistakes.'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;2. sets&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Somewhat related to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;in&lt;/code&gt;, we have sets. I had done many practice problems that could have gone better with the &lt;a href=&quot;https://docs.python.org/3/library/stdtypes.html#set&quot;&gt;set&lt;/a&gt; structure before I learned about it. Sets are non-sequence data structures that contain unordered unique values. They are also super fast at checking for membership. I’ll come back to that in a moment after we take a look at a simple set example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;greet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;hello world&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;set_of_chars&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;greet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;set_of_chars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'There are '&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_of_chars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;' unique characters in '&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;greet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We can make a set by calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set()&lt;/code&gt;, which can take one iterable argument (see below), or by directly listing values in what looks like a list, but with curly braces: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;my_set = {2, 4, 5, 8}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So, why are sets faster at checking for membership than the strategy we used above with the list of course subjects? Because under the hood, a set is a dictionary, which means it is really a hash table. And hash tables are fast. But if you’re thinking that all that heavyweight stuff under the hood of sets makes them bigger than lists, you’d be right. Sets trade space in memory for fast membership tests (&lt;em&gt;O&lt;/em&gt;(1)). Lists are smaller space-wise, but are more like &lt;em&gt;O&lt;/em&gt;(n) to look through each element and test for membership.&lt;/p&gt;

&lt;p&gt;Another flavor of set that Python supports as a built-in data structure is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frozenset()&lt;/code&gt;. This is the same kind of thing as a set, but it is immutable. We might find this useful if we are using constants that can be structured in a set, or if we would like to use a set as a dictionary key.&lt;/p&gt;

&lt;p&gt;One other cool thing is that we can spread iterable objects directly into a set. So:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'buttercup'&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buttercup_set&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Evaluates to a set like this:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;buttercup_set&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'b'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'u'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'t'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'e'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'r'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'c'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'p'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;em&gt;Bonus:&lt;/em&gt; Python somewhat obfuscates another set-related data structure, which is more generally referred to as &lt;a href=&quot;https://en.wikipedia.org/wiki/Multiset&quot;&gt;a bag or multiset&lt;/a&gt; in Computer Science. Python has these stuffed down in the collections module under the name &lt;a href=&quot;https://docs.python.org/3/library/collections.html#collections.Counter&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Counter&lt;/code&gt;&lt;/a&gt;. If you’re looking for this data structure, it already exists in the language! No need to implement your own bag data structure unless that sounds fun.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enumerate()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Oftentimes, we want to loop through a list and have the item along with its index both available in the body of the loop. We can use &lt;a href=&quot;https://docs.python.org/3/library/functions.html#enumerate&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enumerate(iterable)&lt;/code&gt;&lt;/a&gt; to accomplish this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;fruits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'apple'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'orange'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'banoonoo'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fruit&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fruits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fruit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Under the hood, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enumerate()&lt;/code&gt; returns a tuple for each iteration containing the index integer and the item data, which is then unpacked into the index and item variables for use in the loop body.&lt;/p&gt;

&lt;p&gt;One neat thing is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enumerate()&lt;/code&gt; will take iterable objects, such as &lt;a href=&quot;https://docs.python.org/3.1/library/stdtypes.html#typesseq&quot;&gt;sequences&lt;/a&gt; (like strings, lists, tuples, and ranges) and &lt;a href=&quot;https://docs.python.org/3/tutorial/classes.html#iterators&quot;&gt;iterators&lt;/a&gt; (streams of data).&lt;/p&gt;

&lt;p&gt;I never knew how much I needed an operation like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enumerate()&lt;/code&gt; until I studied Lua. In Lua, key-value unpacking of tables (THE Lua data structure) is just a given! It was only when I came back to Python after a few months off that I realized I was looking for this operation.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Bonus:&lt;/em&gt; You might be wondering how &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enumerate()&lt;/code&gt; works on dictionaries, which might not guarantee positional data order the way sequences do. In Python 3, we can unpack key and value with:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;veggies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'carrot'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'onion'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'broccoli'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;veggie&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;veggies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;veggie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Note that we still can’t guarantee the order that the dictionary is looped over, but this syntax will give us both sides of each dict entry.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.join()&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I had seen &lt;a href=&quot;https://docs.python.org/3/library/stdtypes.html#str.join&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str.join()&lt;/code&gt;&lt;/a&gt; in some Stack Overflow answers, but I didn’t realize it was the recommended method for string concatenation until much more recently. I had been using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; operator all this time! &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str.join()&lt;/code&gt; gives us two opportunities to modify the output: we can specify a character that will be inserted in between each item joined by the operation (for instance, spaces, hyphens, or other punctuation that you might want between items), and also the items to be joined. We can use join to unite string fragments into one string, or to join string elements of an iterable into one string:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;letters&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'h'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'e'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'l'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'l'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'o'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;greeting&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;letters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;dash&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'-'&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;greeting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'world'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This produces &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;gt;&amp;gt; hello-world&lt;/code&gt;. First we &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;join&lt;/code&gt; the characters in the “letters” tuple without spaces (‘’). Then we do another &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;join&lt;/code&gt; using a list containing a string and our previously joined string, using dash as a separator.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str.join()&lt;/code&gt; operation is preferable to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; operator for string concatenation because a string is immutable. That means every time we add something to a string with +, Python builds a new string. This can get super inefficient if we do it a lot, like when accumulating string output from a loop. It’s better to use another strategy to accumulate (like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;list.append()&lt;/code&gt;), and then use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;join&lt;/code&gt; at the end to stick it all together as a string outside the loop.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str.join()&lt;/code&gt; operation is useful. It has been hard to retrain myself to use it for simple operations where I am tempted to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt;, but I find I am more likely to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;join()&lt;/code&gt; correctly as I get more familiar with it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. list comprehensions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For some reason, I really struggled to get my mind around &lt;a href=&quot;https://docs.python.org/3/tutorial/datastructures.html?highlight=comprehension#list-comprehensions&quot;&gt;list comprehensions&lt;/a&gt;. Blame bad tutorials, blame being tutored by a C++ programmer, blame a self-diagnosed allergy to comprehension syntax. But more than a year after beginning to study Python, I finally have this one in my toolkit, and what a powerful addition it is!&lt;/p&gt;

&lt;p&gt;Here’s the usual example, mapping sections of the logic to their location in a standard loop versus a list comprehension:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# A normal accumulator pattern
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;accumulator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conditional&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;accumulator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# List comprehension
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;accumulator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conditional&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I’ve shown an accumulator pattern here, because that was the most useful for me. But list comprehensions do all kinds of cool things, like math, nested loops, and nested comprehensions (comprehensions &lt;em&gt;in&lt;/em&gt; comprehensions: *inception horn*). But the biggest thing for me was learning that it is okay to sometimes &lt;em&gt;not&lt;/em&gt; use list comprehensions. Sometimes they won’t work as elegantly as you might want, and sometimes it’s best to leave the old style for better readability.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Bonus:&lt;/em&gt; List comprehensions come in two more flavors. You can use the same syntax with sets and dictionaries. Comprehend all the things!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for ... else&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What!? Did you know &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for&lt;/code&gt; loops can have elses? This blew my mind when I found out. Basically, if we go around all the loops of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for&lt;/code&gt; loop without a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;break&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;return&lt;/code&gt; statement, the code in the else clause is executed. That also means the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;else&lt;/code&gt; clause runs if the loop is executed zero times. This is useful when using a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for&lt;/code&gt; loop to check for some condition — it is useful to prove the value, but it is also useful to get some control flow when the condition was not true for any loop, and therefore false.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;abc123&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isupper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Nice!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iter()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Python gets some of its power from iterable objects, and we iterate through strings by character and lists by item all the time. But I didn’t know that you could explicitly use the built-in function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iter()&lt;/code&gt; to take an iterable object and return an iterator. So what’s an iterator, and why would we want to do that?&lt;/p&gt;

&lt;p&gt;We might want to send an iterator to a function as an argument, and delay the processing of that iterator until we’re inside the function. Like:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;hello world&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'h'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'e'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'l'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'l'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'o'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;' '&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'w'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'o'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'r'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'l'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'d'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This assigns the string &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;hello world&quot;&lt;/code&gt; to an iterable, but we don’t unpack it until we’re inside the bar function, unpacking the iterable into a list. We’ll see this again in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zip()&lt;/code&gt;, but it’s a nice way of passing around an iterable chunk of data without having it processed by each function.&lt;/p&gt;

&lt;p&gt;Another thing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iter()&lt;/code&gt; is useful for is custom behavior. We might want to write a custom class that can be looped through. We can do this in a Pythonic way by mimicking what Python does — implement an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__iter__&lt;/code&gt; method, and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__next__&lt;/code&gt; method that supports incrementation and concludes the iteration appropriately.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iter()&lt;/code&gt; function is pretty simple, but our next two examples depend on it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zip()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://docs.python.org/3/library/functions.html#zip&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zip()&lt;/code&gt;&lt;/a&gt; function returns an iterator that loops over tuples built from two other iterable objects. Whoah, that’s a lot of Python-y buzzwords. Basically, you can construct a new object which combines data from two other objects. For me personally, this has been most understandable and usable when I want to take two lists and make them into a dictionary:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cookies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'samoa'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'trefoil'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'thin mint'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'tagalong'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cookies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now, this will result in the totally useless-looking output&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;zip&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x01FB7609&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;or something. That’s the iterator object. We’ll need to unpack it into another structure to use it. So:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cookies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'samoa'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'trefoil'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'thin mint'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'tagalong'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cookies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'samoa'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'trefoil'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'thin mint'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'tagalong'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;To me, casting the output of the zip iterator to a dict is typically most useful, but I also printed out the example using a list. Casting zipped tuples into a list lets you see that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zip()&lt;/code&gt; really is building two-part tuples with each index of your iterable inputs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. generators&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A generator is a kind of iterator. I learned to recognize them early by their dead giveaway: the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt; keyword. It took me longer to understand some of the things I can do with generators.&lt;/p&gt;

&lt;p&gt;Generators produce a sequence of results, one result per yield statement-execution, instead of the single object returned by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iter()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Generators are useful for lazy evaluation, where the evaluation is delayed until its value is needed, so as to avoid repeat evaluations. When you call generators, you specify how much of the sequence you would like to compute. This is really nice if you have an infinite sequence and only want the first hundred return values:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fizzbuzz&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;fizzbuzz&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;fizz&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;buzz&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first_hundred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This produces a string output for FizzBuzz for the range (0,100]. Other common applications of generators are processing number-theory sequences like the Fibonacci sequence, or sequences of squares, or Pythagorean triples.&lt;/p&gt;

&lt;p&gt;That’s mostly what I have used generators for. They can also be used for more advanced concepts. I encourage you to do more research about generators if you’re interested!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Bonus:&lt;/em&gt; We can also make generator expressions, which are similar to list comprehensions but result in a generator with the given parameters instead of a list.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;repr&lt;/code&gt; vs. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__repr__&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;___str___&lt;/code&gt; are methods of Python classes. Both are used to represent instances of the class as printed output.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__repr__&lt;/code&gt; method is the “canonical” string representation of the specific instance. It should contain enough detail that the programmer can reproduce the instance exactly. The printed detail provided by calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__repr__&lt;/code&gt; should be optimized for a programmer working on the code.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__str__&lt;/code&gt; method is a somewhat more general representation of the instance. It builds and returns a string when called. It might contain information about the attributes of that specific instance. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__str__&lt;/code&gt; method should produce text which the end-user of the program might find useful, or at the very least, not alarming.&lt;/p&gt;

&lt;p&gt;These methods are called automatically when you have a print(object) line in your code. print() looks for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__str__&lt;/code&gt; method first, and if it does not find it, falls back to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__repr__&lt;/code&gt;. If neither exist, you get that weird memory address output. If you have both, and want &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__repr__&lt;/code&gt;, you can call it directly by using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;repr()&lt;/code&gt; function.&lt;/p&gt;

&lt;body&gt;
&lt;br /&gt;
&lt;hr /&gt;
&lt;br /&gt;
&lt;/body&gt;

&lt;p&gt;Hopefully you found some value in that things it took me a year to learn in Python! If you found it useful or helpful, I’d appreciate a &lt;a href=&quot;https://twitter.com/ka_amazing/status/871819043837272064&quot;&gt;retweet&lt;/a&gt;. Thanks to my editors, &lt;a href=&quot;https://github.com/eliasdorneles/&quot;&gt;@eliasdorneles&lt;/a&gt; and &lt;a href=&quot;https://github.com/DataBranner&quot;&gt;@DataBranner&lt;/a&gt;.&lt;/p&gt;</content><author><name></name></author><summary type="html">Forgive me for my clickbait title. It’s been a little over a year since I first started learning Python! In the last few months, I have deepened my knowledge of the language considerably, and I’ve discovered some startling gaps. This is the blog post I wish I had read earlier in my Python education, and I hope you find it useful (or maybe just amusing? :flushed:) 1. in Now, I was familiar with in from for loops! But using in alone as a test for membership had not occurred to me in my first year of Python programming. If we have a collection (like a list or a string) and we’d like to see if that collection contains a value or not, we can use: classes = ['English', 'Math', 'Science'] if 'Math' in classes: print('Yay, Math!') if 'History' not in classes: print('Doomed to repeat our mistakes.') 2. sets Somewhat related to in, we have sets. I had done many practice problems that could have gone better with the set structure before I learned about it. Sets are non-sequence data structures that contain unordered unique values. They are also super fast at checking for membership. I’ll come back to that in a moment after we take a look at a simple set example: greet = &quot;hello world&quot; set_of_chars = set() for char in greet: set_of_chars.add(char) print('There are ' + str(len(set_of_chars)) + ' unique characters in ' + greet) We can make a set by calling set(), which can take one iterable argument (see below), or by directly listing values in what looks like a list, but with curly braces: my_set = {2, 4, 5, 8} So, why are sets faster at checking for membership than the strategy we used above with the list of course subjects? Because under the hood, a set is a dictionary, which means it is really a hash table. And hash tables are fast. But if you’re thinking that all that heavyweight stuff under the hood of sets makes them bigger than lists, you’d be right. Sets trade space in memory for fast membership tests (O(1)). Lists are smaller space-wise, but are more like O(n) to look through each element and test for membership. Another flavor of set that Python supports as a built-in data structure is a frozenset(). This is the same kind of thing as a set, but it is immutable. We might find this useful if we are using constants that can be structured in a set, or if we would like to use a set as a dictionary key. One other cool thing is that we can spread iterable objects directly into a set. So: string = 'buttercup' buttercup_set = set(string) Evaluates to a set like this: buttercup_set = {'b', 'u', 't', 'e', 'r', 'c', 'p'} Bonus: Python somewhat obfuscates another set-related data structure, which is more generally referred to as a bag or multiset in Computer Science. Python has these stuffed down in the collections module under the name Counter. If you’re looking for this data structure, it already exists in the language! No need to implement your own bag data structure unless that sounds fun. 3. enumerate() Oftentimes, we want to loop through a list and have the item along with its index both available in the body of the loop. We can use enumerate(iterable) to accomplish this: fruits = ['apple', 'orange', 'banoonoo'] for index, fruit in enumerate(fruits): print(index, fruit) Under the hood, enumerate() returns a tuple for each iteration containing the index integer and the item data, which is then unpacked into the index and item variables for use in the loop body. One neat thing is that enumerate() will take iterable objects, such as sequences (like strings, lists, tuples, and ranges) and iterators (streams of data). I never knew how much I needed an operation like enumerate() until I studied Lua. In Lua, key-value unpacking of tables (THE Lua data structure) is just a given! It was only when I came back to Python after a few months off that I realized I was looking for this operation. Bonus: You might be wondering how enumerate() works on dictionaries, which might not guarantee positional data order the way sequences do. In Python 3, we can unpack key and value with: veggies = {2: 'carrot', 1: 'onion', 5: 'broccoli'} for number, veggie in veggies.items(): print(number, veggie) Note that we still can’t guarantee the order that the dictionary is looped over, but this syntax will give us both sides of each dict entry. 4. .join() instead of + I had seen str.join() in some Stack Overflow answers, but I didn’t realize it was the recommended method for string concatenation until much more recently. I had been using the + operator all this time! str.join() gives us two opportunities to modify the output: we can specify a character that will be inserted in between each item joined by the operation (for instance, spaces, hyphens, or other punctuation that you might want between items), and also the items to be joined. We can use join to unite string fragments into one string, or to join string elements of an iterable into one string: letters = ('h', 'e', 'l', 'l', 'o') greeting = ''.join(letters) dash = '-' print(dash.join([greeting, 'world'])) This produces &amp;gt;&amp;gt; hello-world. First we join the characters in the “letters” tuple without spaces (‘’). Then we do another join using a list containing a string and our previously joined string, using dash as a separator. The str.join() operation is preferable to the + operator for string concatenation because a string is immutable. That means every time we add something to a string with +, Python builds a new string. This can get super inefficient if we do it a lot, like when accumulating string output from a loop. It’s better to use another strategy to accumulate (like list.append()), and then use join at the end to stick it all together as a string outside the loop. The str.join() operation is useful. It has been hard to retrain myself to use it for simple operations where I am tempted to use +, but I find I am more likely to use join() correctly as I get more familiar with it. 5. list comprehensions For some reason, I really struggled to get my mind around list comprehensions. Blame bad tutorials, blame being tutored by a C++ programmer, blame a self-diagnosed allergy to comprehension syntax. But more than a year after beginning to study Python, I finally have this one in my toolkit, and what a powerful addition it is! Here’s the usual example, mapping sections of the logic to their location in a standard loop versus a list comprehension: # A normal accumulator pattern accumulator = [] for item in list: if conditional: accumulator.append(item) # List comprehension accumulator = [item for item in list if conditional] I’ve shown an accumulator pattern here, because that was the most useful for me. But list comprehensions do all kinds of cool things, like math, nested loops, and nested comprehensions (comprehensions in comprehensions: *inception horn*). But the biggest thing for me was learning that it is okay to sometimes not use list comprehensions. Sometimes they won’t work as elegantly as you might want, and sometimes it’s best to leave the old style for better readability. Bonus: List comprehensions come in two more flavors. You can use the same syntax with sets and dictionaries. Comprehend all the things! 6. for ... else What!? Did you know for loops can have elses? This blew my mind when I found out. Basically, if we go around all the loops of a for loop without a break or return statement, the code in the else clause is executed. That also means the else clause runs if the loop is executed zero times. This is useful when using a for loop to check for some condition — it is useful to prove the value, but it is also useful to get some control flow when the condition was not true for any loop, and therefore false. for c in &quot;abc123&quot;: if c.isupper(): break else: return False Nice! 7. iter() Python gets some of its power from iterable objects, and we iterate through strings by character and lists by item all the time. But I didn’t know that you could explicitly use the built-in function iter() to take an iterable object and return an iterator. So what’s an iterator, and why would we want to do that? We might want to send an iterator to a function as an argument, and delay the processing of that iterator until we’re inside the function. Like: def foo(iterable): return iter(iterable) def bar(iterator): return list(iterator) print(bar(foo(&quot;hello world&quot;))) &amp;gt;&amp;gt;['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'] This assigns the string &quot;hello world&quot; to an iterable, but we don’t unpack it until we’re inside the bar function, unpacking the iterable into a list. We’ll see this again in zip(), but it’s a nice way of passing around an iterable chunk of data without having it processed by each function. Another thing iter() is useful for is custom behavior. We might want to write a custom class that can be looped through. We can do this in a Pythonic way by mimicking what Python does — implement an __iter__ method, and the __next__ method that supports incrementation and concludes the iteration appropriately. The iter() function is pretty simple, but our next two examples depend on it. 8. zip() The zip() function returns an iterator that loops over tuples built from two other iterable objects. Whoah, that’s a lot of Python-y buzzwords. Basically, you can construct a new object which combines data from two other objects. For me personally, this has been most understandable and usable when I want to take two lists and make them into a dictionary: numbers = [1, 2, 3, 4] cookies = ['samoa', 'trefoil', 'thin mint', 'tagalong'] print(zip(numbers, cookies)) Now, this will result in the totally useless-looking output &amp;gt;&amp;gt; &amp;lt;zip object at 0x01FB7609&amp;gt; or something. That’s the iterator object. We’ll need to unpack it into another structure to use it. So: print(dict(zip(numbers, cookies))) &amp;gt;&amp;gt;{1: 'samoa', 2: 'trefoil', 3: 'thin mint', 4: 'tagalong'} print(list(zip(numbers, cookies))) &amp;gt;&amp;gt;[(1, 'samoa'), (2, 'trefoil'), (3, 'thin mint'), (4, 'tagalong')] To me, casting the output of the zip iterator to a dict is typically most useful, but I also printed out the example using a list. Casting zipped tuples into a list lets you see that zip() really is building two-part tuples with each index of your iterable inputs. 9. generators A generator is a kind of iterator. I learned to recognize them early by their dead giveaway: the yield keyword. It took me longer to understand some of the things I can do with generators. Generators produce a sequence of results, one result per yield statement-execution, instead of the single object returned by iter(). Generators are useful for lazy evaluation, where the evaluation is delayed until its value is needed, so as to avoid repeat evaluations. When you call generators, you specify how much of the sequence you would like to compute. This is really nice if you have an infinite sequence and only want the first hundred return values: def fizzbuzz(): i = 1 x = None while i &amp;gt;=0: if i % 15 == 0: x = &quot;fizzbuzz&quot; elif i % 3 == 0: x = &quot;fizz&quot; elif i % 5 == 0: x = &quot;buzz&quot; else: x = str(i) yield x i = i + 1 def first_hundred(iterator): for x in range(100): print(next(iterator)) This produces a string output for FizzBuzz for the range (0,100]. Other common applications of generators are processing number-theory sequences like the Fibonacci sequence, or sequences of squares, or Pythagorean triples. That’s mostly what I have used generators for. They can also be used for more advanced concepts. I encourage you to do more research about generators if you’re interested! Bonus: We can also make generator expressions, which are similar to list comprehensions but result in a generator with the given parameters instead of a list. 10. repr vs. str __repr__ and ___str___ are methods of Python classes. Both are used to represent instances of the class as printed output. The __repr__ method is the “canonical” string representation of the specific instance. It should contain enough detail that the programmer can reproduce the instance exactly. The printed detail provided by calling __repr__ should be optimized for a programmer working on the code. The __str__ method is a somewhat more general representation of the instance. It builds and returns a string when called. It might contain information about the attributes of that specific instance. The __str__ method should produce text which the end-user of the program might find useful, or at the very least, not alarming. These methods are called automatically when you have a print(object) line in your code. print() looks for the __str__ method first, and if it does not find it, falls back to __repr__. If neither exist, you get that weird memory address output. If you have both, and want __repr__, you can call it directly by using the repr() function. Hopefully you found some value in that things it took me a year to learn in Python! If you found it useful or helpful, I’d appreciate a retweet. Thanks to my editors, @eliasdorneles and @DataBranner.</summary></entry><entry><title type="html">Ludum Dare 38 Jam Entry</title><link href="http://katieamazing.com/blog/2017/04/25/LD38" rel="alternate" type="text/html" title="Ludum Dare 38 Jam Entry" /><published>2017-04-25T00:00:00+00:00</published><updated>2017-04-25T00:00:00+00:00</updated><id>http://katieamazing.com/blog/2017/04/25/LD38</id><content type="html" xml:base="http://katieamazing.com/blog/2017/04/25/LD38">&lt;p&gt;Once again, I participated in the Ludum Dare game jam. I joined the “jam” category, which means I could work with a partner (&lt;a href=&quot;https://twitter.com/Johnicholas&quot;&gt;@Johnicholas&lt;/a&gt;), and have an extra day. So, a game in 72 hours. Except, a catch: I was at a conference all day Saturday, so really more like 48 hours of active time!&lt;/p&gt;

&lt;p&gt;We interpreted the theme of &lt;strong&gt;a small world&lt;/strong&gt; in a pretty typical way, and came up with &lt;strong&gt;Whirled of Words&lt;/strong&gt;, a voice-controlled element balancing game. You can play it &lt;a href=&quot;https://katieamazing.com/games/LD38/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://katieamazing.com/games/LD38/&quot;&gt;&lt;img src=&quot;/games/LD38/basegame.jpg&quot; alt=&quot;Click this image to see Whirled of Words in action&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you also participated in Ludum Dare this time around, you can make my day: &lt;a href=&quot;https://ldjam.com/events/ludum-dare/38/whirled-of-words-1&quot;&gt;leave me a comment and rate the game at the website.&lt;/a&gt; Thank you!&lt;/p&gt;

&lt;p&gt;The most pleasing thing for me was how this entry tied together many of my educational efforts over the last weeks and months.&lt;/p&gt;

&lt;p&gt;I had recently completed a &lt;a href=&quot;http://katieamazing.com/blog/2017/02/24/moon-sugar&quot;&gt;JavaScript game&lt;/a&gt; that went pretty well, and that I did very little visual art for. I ran with that for this Ludum Dare. I had a conference to attend from 8am-5pm on Friday and Saturday, so I knew I would have less time than usual, even doing the 72-hour Jam. So choosing to stay out of Photoshop was a time-saving and energy-saving step that really worked out.&lt;/p&gt;

&lt;p&gt;I used SVG for the first time ever (!) to do all the graphics. A few days before, I randomly spent a couple hours at the Recurse Center pairing with a batchmate who was exploring SVG for the first time. I did this without Ludum Dare in mind, but I used a lot of the orientation to SVG I got during that pairing to make the game. I used Inkscape to generate the SVG code for the sprites.&lt;/p&gt;

&lt;p&gt;We used vanilla JavaScript to do all of the coding. Back in January when I was doing Wes Bos’s &lt;a href=&quot;https://javascript30.com/&quot;&gt;JavaScript30&lt;/a&gt; course, I was inspired by the demonstration of the built-in browser support for voice recognition. I held onto that inspiration for the next Ludum Dare. This is the first time a commitment to a specific technology/technique before the theme announcement has not bitten me in the ass during the Ludum weekend. I was really pleased with the scope, complexity, and flexibility of using JavaScript and voice recognition.&lt;/p&gt;

&lt;p&gt;As always, there are things that didn’t go as planned.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;I had hoped to do more physics animation of the SVG elements. I looked into some libraries to do this, but we ended up not having time to implement very much extra.&lt;/li&gt;
  &lt;li&gt;Just ran out of time on UI/background polishing stuff. It is functional, but I think it could be cooler.&lt;/li&gt;
  &lt;li&gt;We didn’t add any sound at all - this was semi-intentional, as we imagined that adding sound effects and music might interfere with the voice recognition, but I still missed doing it. Sound really adds a lot to a game!&lt;/li&gt;
  &lt;li&gt;And finally, submitting to this particular LD was a stressful nightmare. The Ludum Dare site is still significantly under construction, and that was really unpleasant to deal with after a long day of work on the game.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But we did it! Yay LD38, another one for my memory books!&lt;/p&gt;</content><author><name></name></author><summary type="html">Once again, I participated in the Ludum Dare game jam. I joined the “jam” category, which means I could work with a partner (@Johnicholas), and have an extra day. So, a game in 72 hours. Except, a catch: I was at a conference all day Saturday, so really more like 48 hours of active time! We interpreted the theme of a small world in a pretty typical way, and came up with Whirled of Words, a voice-controlled element balancing game. You can play it here. If you also participated in Ludum Dare this time around, you can make my day: leave me a comment and rate the game at the website. Thank you! The most pleasing thing for me was how this entry tied together many of my educational efforts over the last weeks and months. I had recently completed a JavaScript game that went pretty well, and that I did very little visual art for. I ran with that for this Ludum Dare. I had a conference to attend from 8am-5pm on Friday and Saturday, so I knew I would have less time than usual, even doing the 72-hour Jam. So choosing to stay out of Photoshop was a time-saving and energy-saving step that really worked out. I used SVG for the first time ever (!) to do all the graphics. A few days before, I randomly spent a couple hours at the Recurse Center pairing with a batchmate who was exploring SVG for the first time. I did this without Ludum Dare in mind, but I used a lot of the orientation to SVG I got during that pairing to make the game. I used Inkscape to generate the SVG code for the sprites. We used vanilla JavaScript to do all of the coding. Back in January when I was doing Wes Bos’s JavaScript30 course, I was inspired by the demonstration of the built-in browser support for voice recognition. I held onto that inspiration for the next Ludum Dare. This is the first time a commitment to a specific technology/technique before the theme announcement has not bitten me in the ass during the Ludum weekend. I was really pleased with the scope, complexity, and flexibility of using JavaScript and voice recognition. As always, there are things that didn’t go as planned. I had hoped to do more physics animation of the SVG elements. I looked into some libraries to do this, but we ended up not having time to implement very much extra. Just ran out of time on UI/background polishing stuff. It is functional, but I think it could be cooler. We didn’t add any sound at all - this was semi-intentional, as we imagined that adding sound effects and music might interfere with the voice recognition, but I still missed doing it. Sound really adds a lot to a game! And finally, submitting to this particular LD was a stressful nightmare. The Ludum Dare site is still significantly under construction, and that was really unpleasant to deal with after a long day of work on the game. But we did it! Yay LD38, another one for my memory books!</summary></entry></feed>