<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: David Newberry</title>
    <description>The latest articles on Forem by David Newberry (@paxfeline).</description>
    <link>https://forem.com/paxfeline</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F86500%2F37e61e50-8cc5-4eb1-86b5-dd7f1893fe0e.jpeg</url>
      <title>Forem: David Newberry</title>
      <link>https://forem.com/paxfeline</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/paxfeline"/>
    <language>en</language>
    <item>
      <title>Pygame Snake, Pt. 3</title>
      <dc:creator>David Newberry</dc:creator>
      <pubDate>Tue, 21 Apr 2026 23:25:18 +0000</pubDate>
      <link>https://forem.com/paxfeline/pygame-snake-pt-3-27np</link>
      <guid>https://forem.com/paxfeline/pygame-snake-pt-3-27np</guid>
      <description>&lt;p&gt;Part 2 left off with a square moving on a grid. Now, let's take control of it by consuming &lt;code&gt;KEYDOWN&lt;/code&gt; events.&lt;/p&gt;

&lt;p&gt;One simple approach would be to have a variable that represents one of the four directions the snake can go. It might use values 0-3, or it could use string literals like "up" and "left".&lt;/p&gt;

&lt;p&gt;A slightly more advanced technique would be to use the &lt;code&gt;Vector2&lt;/code&gt; class. We use pygame's &lt;code&gt;Vector2&lt;/code&gt; to keep track of the position of out snake part. We could also use a &lt;code&gt;Vector2&lt;/code&gt; to represent the snake's speed and direction. For example, the direction right would be represented by &lt;code&gt;Vector2(1, 0)&lt;/code&gt;, because if we add that vector to the current position, it will increase the &lt;code&gt;x&lt;/code&gt; value (the first coordinate) by 1.&lt;/p&gt;

&lt;p&gt;Left would be &lt;code&gt;Vector2(-1, 0)&lt;/code&gt;. Up and down would be &lt;code&gt;Vector2(0, -1)&lt;/code&gt; and &lt;code&gt;Vector2(0, 1)&lt;/code&gt;, respectively. If up and down seem backwards, it's because in pygame (which uses a common computer drawing convention) the Y-axis increases as you go down, instead of up. The origin is the canvas's upper-left corner.&lt;/p&gt;

&lt;p&gt;Add a new variable under &lt;code&gt;dot&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;vel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the &lt;code&gt;for&lt;/code&gt; loop that consumes events, add the following under the first &lt;code&gt;if&lt;/code&gt; statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KEYDOWN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;K_RIGHT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;vel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;K_DOWN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;vel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;K_LEFT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;vel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;K_UP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;vel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, update the line of code that moves &lt;code&gt;dot&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="err"&gt;﻿&lt;/span&gt;&lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;vel&lt;/span&gt; &lt;span class="c1"&gt;# or dot += vel
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you run your program now, you should be able to control the dot's movement with the arrow keys.&lt;/p&gt;

&lt;p&gt;Full code at this point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;

&lt;span class="n"&gt;W&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
&lt;span class="n"&gt;H&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;

&lt;span class="c1"&gt;# pygame setup
&lt;/span&gt;&lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_mode&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;H&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;clock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Clock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

&lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;H&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;vel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# poll for events
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="c1"&gt;# pygame.QUIT = user closed window
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QUIT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KEYDOWN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;K_RIGHT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;vel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;K_DOWN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;vel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;K_LEFT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;vel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;K_UP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;vel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# fill buffer with white
&lt;/span&gt;    &lt;span class="n"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;white&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;vel&lt;/span&gt;
    &lt;span class="n"&gt;square&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Rect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;black&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# copy buffer to screen
&lt;/span&gt;    &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# limits FPS
&lt;/span&gt;    &lt;span class="n"&gt;clock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OK, that's fine, but we could really tighten it up by introducing a dictionary to hold the key/velocity associations. Like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;key_vel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;K_RIGHT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;K_DOWN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;K_LEFT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;K_UP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add that just above the &lt;code&gt;while&lt;/code&gt; loop. Now the whole &lt;code&gt;KEYDOWN&lt;/code&gt; &lt;code&gt;if&lt;/code&gt; statement can be replaced with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KEYDOWN&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;key_vel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;vel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;key_vel&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When &lt;code&gt;in&lt;/code&gt; is used with a dictionary like this, it checks the dictionary's keys to see if they contain the given value.&lt;/p&gt;

&lt;p&gt;Full code now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;

&lt;span class="n"&gt;W&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
&lt;span class="n"&gt;H&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;

&lt;span class="c1"&gt;# pygame setup
&lt;/span&gt;&lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_mode&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;H&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;clock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Clock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

&lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;H&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;vel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;key_vel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;K_RIGHT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;K_DOWN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;K_LEFT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;K_UP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# poll for events
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="c1"&gt;# pygame.QUIT = user closed window
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QUIT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KEYDOWN&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;key_vel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;vel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;key_vel&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# fill buffer with white
&lt;/span&gt;    &lt;span class="n"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;white&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;vel&lt;/span&gt;
    &lt;span class="n"&gt;square&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Rect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;black&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# copy buffer to screen
&lt;/span&gt;    &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# limits FPS
&lt;/span&gt;    &lt;span class="n"&gt;clock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>beginners</category>
      <category>gamedev</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Pygame Snake, Pt. 2</title>
      <dc:creator>David Newberry</dc:creator>
      <pubDate>Tue, 21 Apr 2026 22:23:58 +0000</pubDate>
      <link>https://forem.com/paxfeline/pygame-snake-pt-2-362l</link>
      <guid>https://forem.com/paxfeline/pygame-snake-pt-2-362l</guid>
      <description>&lt;p&gt;In part 1, we just got pygame going. We have a 1000x1000 pixel canvas, with a 50x50 square moving more-or-less continuously. Snake is played on a fixed grid.&lt;/p&gt;

&lt;p&gt;Instead of 50x50 pixels, we'll shrink the snake parts/tiles to 20x20, and we'll shrink the canvas to 600x600 pixels, treated as a 30x30 grid. (30 tiles x 20 pixels = 600 pixels.)&lt;/p&gt;

&lt;p&gt;We'll add three variables to represent these values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;W&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="c1"&gt;# width
&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="c1"&gt;# height
&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="c1"&gt;# tile size
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we should replace all other numbers in the code with references to these values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_mode&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;H&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;H&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# approx. the center
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="n"&gt;square&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Rect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These values are referenced in several places in the code. By using variables, you can update them in one place and it will be reflected everywhere. You can easily change the width, height, or tile size.&lt;/p&gt;

&lt;p&gt;Add this just above &lt;code&gt;square = ...&lt;/code&gt; (the line shown above):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full code at this point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;

&lt;span class="n"&gt;W&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
&lt;span class="n"&gt;H&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;

&lt;span class="c1"&gt;# pygame setup
&lt;/span&gt;&lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_mode&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;H&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;clock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Clock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

&lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;H&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# poll for events
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="c1"&gt;# pygame.QUIT = user closed window
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QUIT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="c1"&gt;# fill buffer with white
&lt;/span&gt;    &lt;span class="n"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;white&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;dot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;square&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Rect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;black&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# copy buffer to screen
&lt;/span&gt;    &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# limits FPS
&lt;/span&gt;    &lt;span class="n"&gt;clock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are treating the board itself as a 30x30 grid of 1x1 tiles. It is then being scaled up when being drawn. The code &lt;code&gt;dot * S&lt;/code&gt; takes the &lt;code&gt;Vector2&lt;/code&gt; variable with a value like (15, 15). Assuming &lt;code&gt;S = 20&lt;/code&gt;, &lt;code&gt;dot * S&lt;/code&gt; would then produce the point (300, 300), i.e. (15 * 20, 15 * 20).&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>gamedev</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Pygame Snake, Pt. 1</title>
      <dc:creator>David Newberry</dc:creator>
      <pubDate>Tue, 21 Apr 2026 20:50:00 +0000</pubDate>
      <link>https://forem.com/paxfeline/pygame-snake-pt-1-51j4</link>
      <guid>https://forem.com/paxfeline/pygame-snake-pt-1-51j4</guid>
      <description>&lt;p&gt;Pygame is a module designed to allow us to make 2D games using Python. I am just learning pygame myself. I've always loved the game Snake, and I find that it makes a good learning project, too.&lt;/p&gt;

&lt;p&gt;When using pygame, we will draw each frame of our animation to an offscreen buffer. That is basically like an invisible canvas that exists in memory. This allows us to draw the scene piece by piece, and then when its done copy the whole buffer to the onscreen canvas.&lt;/p&gt;

&lt;p&gt;Pygame will also handle the event loop. We can specify how many frames per second we want our game to run at, and pygame will make sure the event loop runs no faster than that. Each time through the loop, we will draw one frame of animation.&lt;/p&gt;

&lt;p&gt;We will also respond to events that pygame gives us. In particular, pygame will send us a KEYDOWN event whenever a key is pressed. Also, if the user closes the pygame window, it will send us a QUIT event, and the game should stop.&lt;/p&gt;

&lt;p&gt;Here is a minimal pygame setup. Modified code from &lt;a href="https://www.pygame.org/docs/" rel="noopener noreferrer"&gt;https://www.pygame.org/docs/&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;

&lt;span class="c1"&gt;# initialize pygame
&lt;/span&gt;&lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# create 1000x1000 pixel pygame window
&lt;/span&gt;&lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_mode&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# clock used to set FPS
&lt;/span&gt;&lt;span class="n"&gt;clock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Clock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# game runs as long as this is True
&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# poll for events
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="c1"&gt;# pygame.QUIT = user closed window
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QUIT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="c1"&gt;# fill buffer with white
&lt;/span&gt;    &lt;span class="n"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;white&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# copy buffer to screen
&lt;/span&gt;    &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# limits FPS
&lt;/span&gt;    &lt;span class="n"&gt;clock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only thing about this code I don't like is that it requires the &lt;code&gt;running&lt;/code&gt; variable. I wanted to use an infinite loop with &lt;code&gt;break&lt;/code&gt;, but I can't do that since we have to iterate through potentially multiple events using an inner (&lt;code&gt;for&lt;/code&gt;) loop, and Python has no way to break out of nested loops.&lt;/p&gt;

&lt;p&gt;OK, so that's not a bad start, except that it is not exactly the most interesting "animation". Let's add a moving square.&lt;/p&gt;

&lt;p&gt;To have an animated square, we'll need a new variable to keep track of its location. If we weren't using pygame, I might create a simple little class for this (to store x and y coordinates). But pygame already has such a class built-in: &lt;code&gt;Vector2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So let's add a new variable called &lt;code&gt;dot&lt;/code&gt; and create a &lt;code&gt;Vector2&lt;/code&gt; value for it to hold:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add that code just above the &lt;code&gt;while&lt;/code&gt; loop.&lt;/p&gt;

&lt;p&gt;Now inside the loop increment &lt;code&gt;dot&lt;/code&gt;'s &lt;code&gt;x&lt;/code&gt; value, and then draw it at its new position. To draw a square, we have to create a &lt;code&gt;Rect&lt;/code&gt; object. To do this, we will pass two pairs of values: the (x, y) coordinates of its upper-left corner, and its (width, height) values. The dot variable itself will function as the (x, y) coordinates of the square's upper-left corner.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="n"&gt;dot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
    &lt;span class="n"&gt;square&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Rect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;black&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Place this code right under &lt;code&gt;screen.fill("white")&lt;/code&gt;. That command paints the entire buffer white, in anticipation of drawing a new frame. The new three lines of code draw a 50x50 black square at the location indicated by the &lt;code&gt;dot&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;Full code now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;

&lt;span class="c1"&gt;# pygame setup
&lt;/span&gt;&lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_mode&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;clock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Clock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

&lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# poll for events
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="c1"&gt;# pygame.QUIT = user closed window
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QUIT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="c1"&gt;# fill buffer with white
&lt;/span&gt;    &lt;span class="n"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;white&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;dot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
    &lt;span class="n"&gt;square&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Rect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;black&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# copy buffer to screen
&lt;/span&gt;    &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# limits FPS
&lt;/span&gt;    &lt;span class="n"&gt;clock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have a little experience with Python, try this challenge: Add some code to check if dot.x &amp;gt; 1000, and if so, set it to 0. This should cause the dot to reappear on the left once it goes off the right edge.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>gamedev</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Installing pygame for IDLE on Mac</title>
      <dc:creator>David Newberry</dc:creator>
      <pubDate>Tue, 21 Apr 2026 19:13:08 +0000</pubDate>
      <link>https://forem.com/paxfeline/installing-pygame-for-idle-on-mac-28kb</link>
      <guid>https://forem.com/paxfeline/installing-pygame-for-idle-on-mac-28kb</guid>
      <description>&lt;p&gt;IDLE is the easy-to-use IDE that comes bundled with Python by default. It's not the greatest IDE in the world, but it's been steadily improving with each release.&lt;/p&gt;

&lt;p&gt;If you work a lot with Python, you might also have &lt;code&gt;conda&lt;/code&gt; installed, or something similar, to create virtual environments with different Python versions and packaged installed. Working in IDLE is going to sidestep all that.&lt;/p&gt;

&lt;p&gt;If you have ever installed Python from &lt;a href="https://www.python.org/" rel="noopener noreferrer"&gt;https://www.python.org/&lt;/a&gt;, you will have IDLE installed already. If not, go download and install it now. &lt;strong&gt;Note: If you have an older Mac and run into problems, you may need to use Python 3.10 instead of the newest version.&lt;/strong&gt; (This worked for me on my Mac running OS X 12.7.6 "Monterey".)&lt;/p&gt;

&lt;p&gt;The first step requires finding the actual binary associated with IDLE.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Right-click on IDLE and select Show Package Contents.&lt;/li&gt;
&lt;li&gt;Inside the package, open &lt;code&gt;Contents&lt;/code&gt;, then &lt;code&gt;MacOS&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Right-click on &lt;code&gt;Python&lt;/code&gt; and choose Show Original.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now you've located the Python binary for your version of IDLE. Highlight the file and choose Edit -&amp;gt; Copy. The path to the file will probably be something like this:&lt;br&gt;
&lt;code&gt;/Library/Frameworks/Python.framework/Versions/3.14/Resources/Python.app/Contents/MacOS/Python&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The next step is done using the Terminal. Find the Terminal app in /Applications/Utilities/ and launch it.&lt;/p&gt;

&lt;p&gt;Once the Terminal has started up fully and you see the command prompt, start by pasting the file path to the python binary on your clipboard.&lt;/p&gt;

&lt;p&gt;After that, you will type or paste the following (note that it starts with a space):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-U&lt;/span&gt; pygame &lt;span class="nt"&gt;--user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-U&lt;/code&gt; will cause pygame to be upgraded if it's installed already&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--user&lt;/code&gt; will cause pygame to be installed for the current user, rather than for all users&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the whole command will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/Library/Frameworks/Python.framework/Versions/3.14/Resources/Python.app/Contents/MacOS/Python &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-U&lt;/span&gt; pygame &lt;span class="nt"&gt;--user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! If everything goes well, pygame will install and be available inside IDLE. If you run into a problem, leave a comment.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>gamedev</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>React, Git[Hub], and VS Code for Beginners - Video 3</title>
      <dc:creator>David Newberry</dc:creator>
      <pubDate>Thu, 23 Oct 2025 03:26:47 +0000</pubDate>
      <link>https://forem.com/paxfeline/react-github-and-vs-code-for-beginners-video-3-4occ</link>
      <guid>https://forem.com/paxfeline/react-github-and-vs-code-for-beginners-video-3-4occ</guid>
      <description>&lt;p&gt;Video 2 (about 18 min):&lt;br&gt;
&lt;a href="https://youtu.be/e_2t2MNYDFQ" rel="noopener noreferrer"&gt;https://youtu.be/e_2t2MNYDFQ&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;In this video, I start by installing VS Code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I start VS Code, and then open up the React project directory created in the first video.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I spend a minute looking at the file hierarchy of the project, and then open up the source file for a component called Welcome, and use it to talk a little bit about how components work.&lt;/p&gt;

&lt;p&gt;I look a little more at the files. I don't see a files called App.js or App.tsx, which is sometimes the root of the React app. In this case, I overlooked &lt;code&gt;root.tsx&lt;/code&gt;, so I'll explore that in the next video.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I start the React development server by running:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm run dev&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the browser, I then load the site by visiting the URL printed in the terminal; as I recall, localhost:5173.&lt;/p&gt;

&lt;p&gt;Finally for this video, I go back to the source in VS Code and demonstrate how the React dev server takes care of essentially refreshing and "Hot [Re]loading" the content that gets changed, if you edit the source code.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the next video installment, I plan to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new branch in git&lt;/li&gt;
&lt;li&gt;Create a new React component&lt;/li&gt;
&lt;li&gt;Discuss how state is handled in React&lt;/li&gt;
&lt;li&gt;Merge the working branch into main*&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(*) As it happens, I didn't have time in that stream! But next time, for sure.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>beginners</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>React, Git[Hub], and VS Code for Beginners - Video 3</title>
      <dc:creator>David Newberry</dc:creator>
      <pubDate>Thu, 23 Oct 2025 03:26:47 +0000</pubDate>
      <link>https://forem.com/paxfeline/react-github-and-vs-code-for-beginners-video-3-32bj</link>
      <guid>https://forem.com/paxfeline/react-github-and-vs-code-for-beginners-video-3-32bj</guid>
      <description>&lt;p&gt;&lt;em&gt;Previous video blog: &lt;a href="https://dev.to/paxfeline/react-github-and-vs-code-for-beginners-video-2-485g"&gt;Part 2&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Video 3 (about 18 min):&lt;br&gt;
(Stream 2)&lt;br&gt;
&lt;a href="https://youtu.be/e_2t2MNYDFQ" rel="noopener noreferrer"&gt;https://youtu.be/e_2t2MNYDFQ&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;In this video, I start by installing VS Code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I start VS Code, and then open up the React project directory created in the first video.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I spend a minute looking at the file hierarchy of the project, and then open up the source file for a component called Welcome, and use it to talk a little bit about how components work.&lt;/p&gt;

&lt;p&gt;I look a little more at the files. I don't see a files called App.js or App.tsx, which is sometimes the root of the React app. In this case, I overlooked &lt;code&gt;root.tsx&lt;/code&gt;, so I'll explore that in the next video.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I start the React development server by running:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm run dev&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the browser, I then load the site by visiting the URL printed in the terminal; as I recall, localhost:5173.&lt;/p&gt;

&lt;p&gt;Finally for this video, I go back to the source in VS Code and demonstrate how the React dev server takes care of essentially refreshing and "Hot [Re]loading" the content that gets changed, if you edit the source code.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the next video installment, I plan to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new branch in git&lt;/li&gt;
&lt;li&gt;Create a new React component&lt;/li&gt;
&lt;li&gt;Discuss how state is handled in React&lt;/li&gt;
&lt;li&gt;Merge the working branch into main*&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(*) As it happens, I didn't have time in that stream! But next time, for sure.&lt;/p&gt;

</description>
      <category>git</category>
      <category>vscode</category>
      <category>beginners</category>
      <category>react</category>
    </item>
    <item>
      <title>React, Git[Hub], and VS Code for Beginners - Video 2</title>
      <dc:creator>David Newberry</dc:creator>
      <pubDate>Thu, 23 Oct 2025 03:13:29 +0000</pubDate>
      <link>https://forem.com/paxfeline/react-github-and-vs-code-for-beginners-video-2-485g</link>
      <guid>https://forem.com/paxfeline/react-github-and-vs-code-for-beginners-video-2-485g</guid>
      <description>&lt;p&gt;&lt;em&gt;Previous video blog: &lt;a href="https://dev.to/paxfeline/react-github-and-vs-code-for-beginners-video-1-18h9"&gt;Part 1&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Video 2:&lt;br&gt;
(Stream 1, Part 2)&lt;br&gt;
&lt;a href="https://youtu.be/Vwr2P7OWAWI" rel="noopener noreferrer"&gt;https://youtu.be/Vwr2P7OWAWI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So now, with luck, you have a React Router app. Before diving into it, create a repository on GitHub.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Signing up for GitHub is pretty straightforward.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Once you have an account, you can create a new repository.&lt;/p&gt;

&lt;p&gt;Most of the default settings are fine. For simplicity I named it the same thing as my local repository. I did not include anything in the initial repo, because all the files I want to upload will come from the local repo.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next I tried to follow the instructs to push connect the local repository to the remote repo and push the changes, but I ran into a snag. I needed to authenticate git to GitHub.&lt;/p&gt;

&lt;p&gt;The solution I eventually found was to install the GitHub CLI tool, which is a separate binary from &lt;code&gt;git&lt;/code&gt;, called &lt;code&gt;gh&lt;/code&gt;. There were a few options for installing &lt;code&gt;gh&lt;/code&gt;. I chose to download the binary and then run it by &lt;code&gt;cd&lt;/code&gt;-ing into the directory and running:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;./gh auth login
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The &lt;code&gt;./gh&lt;/code&gt; indicates that I want to run a binary in my current working directory.&lt;/p&gt;

&lt;p&gt;Another good option would be to first install Homebrew, and then use it to install &lt;code&gt;gh&lt;/code&gt;. On my primary development computer I have Homebrew installed. I don't have to avail myself of it often, but I probably end up using it a few times a year to install some binary that would be hard to install otherwise.&lt;/p&gt;

&lt;p&gt;Once I'm authenticated with GitHub, I'm able to push my the project.&lt;/p&gt;

&lt;p&gt;I turn next to VS Code, starting the download.&lt;/p&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;That's it for this video. Next time, I actually open VS Code!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Next video blog: &lt;a href="https://dev.to/paxfeline/react-github-and-vs-code-for-beginners-video-3-32bj"&gt;Part 3&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>beginners</category>
      <category>vscode</category>
      <category>react</category>
    </item>
    <item>
      <title>React, Git[Hub], and VS Code for Beginners - Video 1</title>
      <dc:creator>David Newberry</dc:creator>
      <pubDate>Thu, 23 Oct 2025 03:10:45 +0000</pubDate>
      <link>https://forem.com/paxfeline/react-github-and-vs-code-for-beginners-video-1-18h9</link>
      <guid>https://forem.com/paxfeline/react-github-and-vs-code-for-beginners-video-1-18h9</guid>
      <description>&lt;p&gt;React, GitHub, VS Code Video Blog&lt;/p&gt;

&lt;p&gt;This series of blogs is an accompaniment to a weekly coding live-stream that I am doing. This series is focused on the three topics listed above, and is aimed at people who are just getting started. For that reason, I am working on a computer that has never been used for development before, and installing all the software I need along the way.&lt;/p&gt;

&lt;p&gt;I also decided not to rehearse these videos. My hope is that there is value in seeing the messiness of the process, and what it looks like to work through questions and issues in real time. The downside is that sometimes I'll get stuck, or change my mind and backtrack. When I post videos to YouTube, I will edit them a bit for time by speeding up stretches where I'm not talking.&lt;/p&gt;

&lt;p&gt;You can join the weekly live stream Wednesday afternoons (around 1 PM, Pacific) on Twitch, and find past weeks' videos on my YouTube:&lt;br&gt;
&lt;a href="https://www.twitch.tv/paxfeline" rel="noopener noreferrer"&gt;https://www.twitch.tv/paxfeline&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/@GrokProgramming" rel="noopener noreferrer"&gt;https://www.youtube.com/@GrokProgramming&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In these blogs, I will list out the important steps and call out any mistakes I make during the stream.&lt;/p&gt;

&lt;p&gt;Video 1:&lt;br&gt;
(Stream 1, Part 1)&lt;br&gt;
&lt;a href="https://youtu.be/K13tgiff5mo" rel="noopener noreferrer"&gt;https://youtu.be/K13tgiff5mo&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Preliminary: Get git. On Mac, one way to do this is install Xcode.&lt;/p&gt;

&lt;p&gt;If you have no intention of doing app development, or any non-web development, you might want to skip Xcode and get &lt;code&gt;git&lt;/code&gt; directly from &lt;a href="http://git-scm.com/" rel="noopener noreferrer"&gt;http://git-scm.com/&lt;/a&gt;. One way to do this on Mac is to use Homebrew, which is another thing to install, but makes getting some other binaries easier.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In order to run the commands to create a new React app and start the React dev server, I install Node.js, which comes with command line tools npm and npx. To install Node.js, I first installed &lt;code&gt;nvm&lt;/code&gt; -- "node version manager" -- by running:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-o-&lt;/span&gt; https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;(Per &lt;a href="https://github.com/nvm-sh/nvm?tab=readme-ov-file" rel="noopener noreferrer"&gt;https://github.com/nvm-sh/nvm?tab=readme-ov-file&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;When nvm finished installing, it tried to modify my shell &lt;code&gt;.profile&lt;/code&gt; script, which is run whenever a new shell session starts. In particular nvm wants to add some code that will export an environmental variable called &lt;code&gt;NVM_DIR&lt;/code&gt;, and run a script to load nvm.&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;I used the command line program pico to create &lt;code&gt;.profile&lt;/code&gt; and paste in the code nvm told me to, then opened up a new terminal window. This started a new shell session, which executed &lt;code&gt;.profile&lt;/code&gt; (thus exporting the variable and loading nvm).&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Next, I installed Node.js by running &lt;code&gt;nvm install node&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;At that point I could run the command that creates a new React Router app.&lt;/p&gt;

&lt;p&gt;First, in the terminal, navigate to the directory you want to create your new app directory in.&lt;/p&gt;

&lt;p&gt;Beware my mistake! I told the script to create the project at &lt;code&gt;~/first-react-app&lt;/code&gt;. (To be fair, I'm pretty sure the script asked "where" I wanted it.) Generally, a path like that is interpreted as "in the home directory, an entry called first-react-app." However, in this case, in my current working directory (which was my home directory -- so the tilde-slash was redundant), it created a directory named "~" and placed "first-react-app" inside that.&lt;/p&gt;

&lt;p&gt;Don't make my mistake. Navigate to where you want your project, and then just enter the name of the project you're creating.&lt;/p&gt;

&lt;p&gt;The command to create a new React Router app is:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-router@latest my-react-router-app
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;(Per &lt;a href="https://reactrouter.com/start/framework/installation" rel="noopener noreferrer"&gt;https://reactrouter.com/start/framework/installation&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;During the creation process, you will be asked to give your project a name, if you would like to initialize a git repository (you probably do), and a few other questions.&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;To start the React development server, and see your new app, run the following commands to move into the project directory, install necessary packages, and then start the server.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-react-router-app
npm i
npm run dev
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;End of Video 1&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Next video blog: &lt;a href="https://dev.to/paxfeline/react-github-and-vs-code-for-beginners-video-2-485g"&gt;Part 2&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>react</category>
    </item>
    <item>
      <title>Tagged String Literals</title>
      <dc:creator>David Newberry</dc:creator>
      <pubDate>Thu, 13 Feb 2025 18:42:45 +0000</pubDate>
      <link>https://forem.com/paxfeline/tagged-string-literals-4ihd</link>
      <guid>https://forem.com/paxfeline/tagged-string-literals-4ihd</guid>
      <description>&lt;p&gt;I love seeing a line of code and thinking, &lt;em&gt;I can not parse that.&lt;/em&gt; And then learning to parse it.&lt;/p&gt;

&lt;p&gt;This is valid JavaScript:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGiLOHEiakAEO1Xc%3Fformat%3Dpng%26name%3D360x360" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGiLOHEiakAEO1Xc%3Fformat%3Dpng%26name%3D360x360" alt="JavaScript code: console.log raw `foo` endraw " width="338" height="72"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is an instance of using a tagged template string.&lt;/p&gt;

&lt;p&gt;This works too:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGiLO5XLbgAAli57%3Fformat%3Dpng%26name%3Dsmall" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FGiLO5XLbgAAli57%3Fformat%3Dpng%26name%3Dsmall" alt="Another example of using tagged template strings" width="678" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These examples are from &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates" rel="noopener noreferrer"&gt;MDN&lt;/a&gt;. Learn more there. I have no use for this knowledge right now, but one day I may!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Hearsay, part 2: Props</title>
      <dc:creator>David Newberry</dc:creator>
      <pubDate>Wed, 05 Feb 2025 04:25:20 +0000</pubDate>
      <link>https://forem.com/paxfeline/hearsay-part-2-props-h39</link>
      <guid>https://forem.com/paxfeline/hearsay-part-2-props-h39</guid>
      <description>&lt;p&gt;My &lt;a href="https://dev.to/paxfeline/hearsay-talkative-web-components-400o"&gt;previous post on hearsay&lt;/a&gt; discusses how this problem came up for me.&lt;/p&gt;

&lt;p&gt;In hearsay, I want to be able to pass data into components using the &lt;code&gt;props&lt;/code&gt; attribute, and specifying a JavaScript object literal. Something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;hear-say&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"Comp.html"&lt;/span&gt; &lt;span class="na"&gt;props=&lt;/span&gt;&lt;span class="s"&gt;"{ n: Math.random() }"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/hear-say&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's start with the fundamental task: the attribute should be interpreted as JavaScript code. So I created a custom getter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;props&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;    
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prop_att&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;props&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prop_func&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;self&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`return &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;prop_att&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;prop_func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a new function with a single argument &lt;code&gt;self&lt;/code&gt;, and the body of the function simply returns whatever the expression evaluates to. So every time this component accesses &lt;code&gt;self.props.n&lt;/code&gt;, it will call Math.random() and return a new value.&lt;/p&gt;

&lt;p&gt;This is good, but a straightforward setter turned out to be a problem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="nf"&gt;props&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;props&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I tried updating the value of &lt;code&gt;props&lt;/code&gt;, I ran into a problem. A line of code like &lt;code&gt;self.props = { ...self.props }&lt;/code&gt; (never mind accomplishing anything useful) would result in the value changing from &lt;code&gt;{ n: Math.random() }&lt;/code&gt; to, e.g., &lt;code&gt;{ n: 0.42 }&lt;/code&gt;. The code would be overwritten with a value.&lt;/p&gt;

&lt;p&gt;It occurred to me that I could create another property, call it &lt;code&gt;propsData&lt;/code&gt;, that could hold data written to &lt;code&gt;props&lt;/code&gt;. This way you can write whatever you want to &lt;code&gt;props&lt;/code&gt;, and it won't overwrite the code there. &lt;/p&gt;

&lt;p&gt;I changed the setter to store data in &lt;code&gt;propsData&lt;/code&gt;. And it places the data into a &lt;code&gt;props-data&lt;/code&gt; attribute to make it easy to see when inspecting the DOM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="nf"&gt;props&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;propsData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;props-data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's a little weird, the behavior isn't immediately intuitive I'm afraid, but on balance I think it's a good approach. Now I just had to give myself more work.&lt;/p&gt;

&lt;p&gt;I thought it would be nice if the user could update &lt;code&gt;props&lt;/code&gt; (or &lt;code&gt;propsData&lt;/code&gt;, really) by mutating it. The solution that came to mind was to create a special Proxy for &lt;code&gt;props&lt;/code&gt; that also incorporates &lt;code&gt;propsData&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What I want it to do is sort of synthesize &lt;code&gt;props&lt;/code&gt; and &lt;code&gt;propsData&lt;/code&gt;. When code references &lt;code&gt;props.foo&lt;/code&gt;, I want it to check both &lt;code&gt;props&lt;/code&gt; and &lt;code&gt;propsData&lt;/code&gt; for &lt;code&gt;foo&lt;/code&gt;. If it exists in both places, it will prefer the &lt;code&gt;propsData&lt;/code&gt; version. If &lt;code&gt;foo&lt;/code&gt; doesn't exist in &lt;code&gt;propsData&lt;/code&gt;, it will return whatever &lt;code&gt;props.foo&lt;/code&gt; holds (if anything).&lt;/p&gt;

&lt;p&gt;So far so good. But what if &lt;code&gt;props&lt;/code&gt; holds nested objects? Code that sets, e.g., &lt;code&gt;props.foo.bar.baz = 42&lt;/code&gt; will run into an issue. As it goes down the &lt;code&gt;props&lt;/code&gt; chain (getting first &lt;code&gt;foo&lt;/code&gt; and then &lt;code&gt;bar&lt;/code&gt;) the corresponding chain under &lt;code&gt;propsData&lt;/code&gt; is empty (there is no &lt;code&gt;propsData.foo&lt;/code&gt;, much less &lt;code&gt;propsData.foo.bar&lt;/code&gt;). To compensate, if the getter finds an object property in the &lt;code&gt;props&lt;/code&gt; chain and no corresponding &lt;code&gt;propsData&lt;/code&gt; property, it will fill it in with an empty object.&lt;/p&gt;

&lt;p&gt;This is basically how the current version of the code works, with one more provision. When evaluating an expression like &lt;code&gt;props.foo.bar = 42&lt;/code&gt;, &lt;code&gt;foo&lt;/code&gt; will return an object wrapped in a Proxy, which basically holds two things: the value for &lt;code&gt;foo&lt;/code&gt; inside &lt;code&gt;props&lt;/code&gt;, and inside &lt;code&gt;propsData&lt;/code&gt;. This is exactly what it does for the &lt;code&gt;props&lt;/code&gt; chain, but the &lt;code&gt;propsData&lt;/code&gt; chain needs to be a little different.&lt;/p&gt;

&lt;p&gt;At first I had it construct an object with one field for the &lt;code&gt;props&lt;/code&gt; chain and one for the &lt;code&gt;propsData&lt;/code&gt; chain. The Proxy target for &lt;code&gt;foo&lt;/code&gt; in &lt;code&gt;props.foo&lt;/code&gt;, for example, would look like &lt;code&gt;{ props: {bar: 42}, propsData: {} }&lt;/code&gt;. But that leaves the &lt;code&gt;propsData&lt;/code&gt; chain disconnected from &lt;code&gt;propsData&lt;/code&gt;. Instead, the Proxy target changed: a &lt;code&gt;prop&lt;/code&gt; property was added. Now instead of the &lt;code&gt;propsData&lt;/code&gt; property holding the value of, e.g., &lt;code&gt;foo.bar&lt;/code&gt;,  it would hold the value of &lt;code&gt;foo&lt;/code&gt;, and &lt;code&gt;prop&lt;/code&gt; would be &lt;code&gt;bar&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This setup allows a backwards chaining effect. The Proxy for &lt;code&gt;bar&lt;/code&gt; would look like &lt;code&gt;{ props: 42, propsData: propsData.foo, prop: "bar" }&lt;/code&gt;. The Proxy's setter runs &lt;code&gt;target.propsData[target.prop] = val&lt;/code&gt;. &lt;code&gt;target.propsData&lt;/code&gt; will be &lt;code&gt;propsData.foo&lt;/code&gt;, so the effect is the same as setting &lt;code&gt;propsData.foo.bar = val&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I hope you found this post somewhat useful. I fear this explanation is not as clear as I had hoped. If you have any questions, please feel free to comment.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Hearsay: "Talkative Web Components"</title>
      <dc:creator>David Newberry</dc:creator>
      <pubDate>Tue, 04 Feb 2025 02:25:39 +0000</pubDate>
      <link>https://forem.com/paxfeline/hearsay-talkative-web-components-400o</link>
      <guid>https://forem.com/paxfeline/hearsay-talkative-web-components-400o</guid>
      <description>&lt;p&gt;A few years ago, I learned enough React to cobble together a project I had in mind (&lt;a href="https://rifftube.net" rel="noopener noreferrer"&gt;RiffTube&lt;/a&gt;). Some parts of it I liked, and others I didn't. I've always leaned more toward vanilla JavaScript, and been wary of frameworks.&lt;/p&gt;

&lt;p&gt;Recently I began reworking RiffTube, and updating Node packages caused everything to break. I eventually got things working again, but the process reminded me of what I don't love about React.&lt;/p&gt;

&lt;p&gt;The idea for a framework started forming in my mind. There were two core pieces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Components, similar to React&lt;/li&gt;
&lt;li&gt;Communication via broadcasting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It seems to me that React's strategy for handling state is both redundant and at adds with the way JavaScript does everything else. The state of a web app can be specified by listing out all the values of all the variables (such as, and including, all the objects and all their properties).&lt;/p&gt;

&lt;p&gt;React adds another layer of variables, etc., on top of that, which is what seems redundant. And then, when it's "official" state gets updated, it re-renders the component, which seems to me at odds with the JavaScript ethos.&lt;/p&gt;

&lt;p&gt;So I started working on &lt;a href="https://github.com/paxfeline/hearsay/" rel="noopener noreferrer"&gt;hearsay&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In hearsay, there is no "special" state. So if you want a component to do something, like update a property/UI, you can broadcast a message. You can specify a recipient, so that the appropriate recipient can respond -- but every component can "hear" the message, and decide if they need to respond or not.&lt;/p&gt;

&lt;p&gt;Components are implemented with a fairly lightweight &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements" rel="noopener noreferrer"&gt;custom element&lt;/a&gt; (MDN article). The custom element, &lt;code&gt;&amp;lt;hear-say&amp;gt;&lt;/code&gt;, provides a few capabilities and behaviors.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;src&lt;/code&gt; attribute: Specify the path to an HTML file.

&lt;ul&gt;
&lt;li&gt;The contents of this file will be attached as the shadow DOM for the custom element.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; element can be used to call a special &lt;code&gt;setup()&lt;/code&gt; function allowing you to:

&lt;ul&gt;
&lt;li&gt;Attach custom element callbacks.&lt;/li&gt;
&lt;li&gt;Specify a special &lt;code&gt;init()&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;Specify a special &lt;code&gt;react()&lt;/code&gt; method to respond to messages that are broadcast.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;code&gt;slot()&lt;/code&gt; method:&lt;/p&gt;

&lt;p&gt;A helper method for filling slots in the shadow DOM.&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;code&gt;props&lt;/code&gt; attribute:&lt;/p&gt;

&lt;p&gt;Inspired by React, I wanted to be able to pass data into a component. Using this attribute, you can specify an object literal with regular JavaScript code.&lt;/p&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;props&lt;/code&gt; attribute ended up being more complicated to implement than I realized at first. In particular, if &lt;code&gt;props&lt;/code&gt; started out with a value like &lt;code&gt;{ n: Math.random() }&lt;/code&gt;, then doing &lt;code&gt;this.props = { ...this.props, foo: 42 }&lt;/code&gt; would overwrite the code expression with a value, like &lt;code&gt;{ n: 0.123, foo: 42 }&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So I wanted to come up with a way to make using &lt;code&gt;props&lt;/code&gt; easy and intuitive. The solution I came up with involves (what I think is) a pretty neat use of &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy" rel="noopener noreferrer"&gt;Proxy&lt;/a&gt;. The next post will be all about that.&lt;/p&gt;




&lt;p&gt;Here is an example of a very simple hearsay component. It includes code that calls &lt;code&gt;broadcast()&lt;/code&gt;, and also a &lt;code&gt;react()&lt;/code&gt; method that responds to the message.&lt;/p&gt;

&lt;p&gt;Clicker.html:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;init&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;slot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;react&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;slot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Clicker&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    You have clicked
    &lt;span class="nt"&gt;&amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;
    times!
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"broadcast('inc')"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Click
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The HTML file that wants to use this component would include the &lt;code&gt;hearsay.js&lt;/code&gt; script file, and use a &lt;code&gt;&amp;lt;hear-say src="Clicker.html"&amp;gt;&amp;lt;/hear-say&amp;gt;&lt;/code&gt; element to display it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"hearsay.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;hear-say&lt;/span&gt; &lt;span class="na"&gt;struct=&lt;/span&gt;&lt;span class="s"&gt;"Clicker.html"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/hear-say&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;More information and examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/paxfeline/hearsay/" rel="noopener noreferrer"&gt;Hearsay on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also see my &lt;a href="https://github.com/paxfeline/hearsay/blob/main/build-journal.md" rel="noopener noreferrer"&gt;hearsay "build journal"&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Talking to a Gmail POP3 server with Python</title>
      <dc:creator>David Newberry</dc:creator>
      <pubDate>Sat, 07 Sep 2024 18:37:33 +0000</pubDate>
      <link>https://forem.com/paxfeline/talking-to-a-gmail-pop3-server-with-python-59kf</link>
      <guid>https://forem.com/paxfeline/talking-to-a-gmail-pop3-server-with-python-59kf</guid>
      <description>&lt;p&gt;There is a short (under 6 minutes) &lt;a href="https://youtu.be/D4Tj_S2A2Ac" rel="noopener noreferrer"&gt;video to go along with this blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;POP is a relatively old protocol; used to retrieve email from an email server. The first version was specified in 1984. The version still in use today, POP3, was specified in 1996. To try it out, I went about connecting to a Gmail POP3 server.&lt;/p&gt;

&lt;p&gt;The first step was looking up the POP3 settings -- what server to connect to, on what port. Google led me &lt;a href="https://support.google.com/mail/answer/7104828" rel="noopener noreferrer"&gt;here&lt;/a&gt;, where I found the following information.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;pop.gmail.com&lt;/p&gt;

&lt;p&gt;Requires SSL: Yes&lt;/p&gt;

&lt;p&gt;Port: 995&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It mentions that SSL is required. This wasn't something I dealt with 25 years ago, when I was last messing around with POP. I was afraid it would be a headache, but it turned out to be no challenge whatsoever; with a little help from the &lt;a href="https://docs.python.org/3/library/ssl.html" rel="noopener noreferrer"&gt;Python docs&lt;/a&gt;, I arrived at this code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;

&lt;span class="n"&gt;hostname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pop.gmail.com&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_default_context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_connection&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;995&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap_socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;server_hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;version&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It connects, and tells me what version of SSL is in use... or something. Great success! Time to start a conversation with the server.&lt;/p&gt;

&lt;p&gt;Borrowing from the official &lt;a href="https://www.ietf.org/rfc/rfc1939.txt" rel="noopener noreferrer"&gt;RFC for POP3&lt;/a&gt;, here's an example POP3 conversation between a client and server/&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C: &amp;lt;open connection&amp;gt;
S:    +OK POP3 server ready &amp;lt;1896.697170952@dbc.mtview.ca.us&amp;gt;
C:    USER mrose
S:    +OK mrose is a real hoopy frood
C:    PASS secret
S:    +OK mrose's maildrop has 2 messages (320 octets)
C:    STAT
S:    +OK 2 320
C:    LIST
S:    +OK 2 messages (320 octets)
S:    1 120
S:    2 200
S:    .
C:    RETR 1
S:    +OK 120 octets
S:    &amp;lt;the POP3 server sends message 1&amp;gt;
S:    .
C:    QUIT
S:    +OK dewey POP3 server signing off (maildrop empty)
C:  &amp;lt;close connection&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first thing that happens is that the server sends a greeting to the client. Friendly. So I'll add code to receive a message from the server.&lt;/p&gt;

&lt;p&gt;When you ask to receive data from a socket, you have to specify a buffer size. The &lt;a href="https://docs.python.org/3/library/socket.html#socket.socket.recv" rel="noopener noreferrer"&gt;docs&lt;/a&gt; recommend a power of 2, such as 4096. Many responses from the server will come through all at once. Some won't; sometimes a message from the server will be broken across sever reads, and the buffer may not be filled to its maximum even if there is more to come.&lt;/p&gt;

&lt;p&gt;In the case of POP3, the way to tell if a message has come in completely depends on which message is coming in. Most of the time the server is sending a single line of text. (As we will see again later, these have a carriage return and line feed characters at the end of each line.) Certain messages that could have a much longer response use another way to show they're done: a period on a single line by itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;

&lt;span class="n"&gt;hostname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pop.gmail.com&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_default_context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_connection&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;995&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap_socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;server_hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;version&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run again and, we get a greeting. Another great success! Notice that the line ends with "\r\n" -- carriage return and line feed characters.&lt;/p&gt;

&lt;p&gt;You have to pass a buffer size to the read method. It will then have a buffer that size available to read data from the server -- but there's no guarantee of how much data will come into the buffer at a time. This means that a protocol needs some way of specifying when a message is complete. There are numerous strategies possible. POP uses two: for all messages, lines are ended with \r\n. For a short (one line) message, this is all that's required. For multi-line responses, a period on a line by itself indicates that the message is complete.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TLSv1.3
b'+OK Gpop ready for requests from 2601:1c0:8301:b590:f408:d66a:3029:16ad dq2mb54750689ivb\r\n'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we need to start talking back to the server. Time to create an I/O (or O/I) loop; get some user input and send it to the server. Oops! I can't send a string directly; that gives me a TypeError. I need to convert the message to bytes. The string encode() method will do that (the default encoding of utf-8 works fine).&lt;/p&gt;

&lt;p&gt;Only, when I run it -- oops again! Nothing happens when my message is sent to the server. Because I forgot that messages coming from the client also need to end with \r\n. Another tiny tweak gives us:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;

&lt;span class="n"&gt;hostname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pop.gmail.com&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_default_context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_connection&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;995&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap_socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;server_hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;version&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, now I can actually try to log in!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TLSv1.3
b'+OK Gpop ready for requests from 2601:1c0:8301:b590:f408:d66a:3029:16ad g4mb5147337iow\r\n'
USER grokprogramming
b'+OK send PASS\r\n'
PASS trustno1
b'-ERR [AUTH] Application-specific password required: https://support.google.com/accounts/answer/185833\r\n'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OK, so following that link takes me to a page where I can set up an application specific password. One potential stumbling block I came across: your account has to have two-factor authentication turned on in order for you to be able to make an application specific password, as far as I can tell. Why would I &lt;em&gt;not&lt;/em&gt; have two-factor authentication turned on in the year of our Lorde 2024? I can't say. I do now.&lt;/p&gt;

&lt;p&gt;Armed with an application specific password (mind you take out the spaces), I can log in! Then I'll issue the STAT command which will tell me how many messages I have, and their combined size. After that, I'll issue the LIST command, which will return a list of messages with an ID and a size for each one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TLSv1.3
b'+OK Gpop ready for requests from 2601:1c0:8301:b590:f408:d66a:3029:16ad e18mb76868856iow\r\n'
USER grokprogramming
b'+OK send PASS\r\n'
PASS baygdsgkmihkckrb
b'+OK Welcome.\r\n'
STAT
b'+OK 263 14191565\r\n'
LIST
b'+OK 263 messages (14191565 bytes)\r\n1 2778\r\n2 2947\r\n3 6558\r\n4 9864\r\n5 35997\r\n6 45462\r\n7 45462\r\n8 63894\r\n9 11487\r\n10 74936\r\n11 74925\r\n12 11632\r\n13 32392\r\n14 74997\r\n15 51961\r\n16 15375\r\n17 46513\r\n18 21519\r\n19 15966\r\n20 27258\r\n21 28503\r\n22 35615\r\n23 86353\r\n24 280'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've hit a bug in the code. The response for LIST spans multiple lines and, in this case, will require multiple buffer reads. The whole message will end with a period on a line by itself. Here I've received one buffer worth of the message, and now I'll have to hit return and send a blank message to the server in order for the code to advance to the next iteration of the loop and read from the buffer again.&lt;/p&gt;

&lt;p&gt;I'll tweak the code so that the user always has the option of reading from the buffer again, or not. I'll also finally decode the incoming bytes from the server, so that the text renders nicer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;

&lt;span class="n"&gt;hostname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pop.gmail.com&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_default_context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_connection&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;995&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap_socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;server_hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;version&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;more? y/[n]: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here's a full session including retrieving an email and sending the disconnect message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; USER grokprogramming
+OK send PASS

more? y/[n]: 
&amp;gt; PASS trustno1
+OK Welcome.

more? y/[n]: 
&amp;gt; STAT
+OK 263 14191565

more? y/[n]: 
&amp;gt; LIST
+OK 263 messages (14191565 bytes)
1 2778
2 2947
3 6558
&amp;lt;...&amp;gt;
260 41300
261 114059
262 174321
263 39206
.

more? y/[n]: 
&amp;gt; RETR 1
+OK message follows
MIME-Version: 1.0
Received: by 10.76.81.230; Thu, 28 Jun 2012 20:21:50 -0700 (PDT)
Date: Thu, 28 Jun 2012 20:21:50 -0700
Message-ID: &amp;lt;CADBp03TWFOKcTOaK_0P7VV2GB+TZsoSd_W4G5nZKKs7pdk6cWQ@mail.gmail.com&amp;gt;
Subject: Customize Gmail with colors and themes
From: Gmail Team &amp;lt;mail-noreply@google.com&amp;gt;
To: Grok Programming &amp;lt;grokprogramming@gmail.com&amp;gt;
Content-Type: multipart/alternative; boundary=e0cb4e385592f8025004c393f2b4

--e0cb4e385592f8025004c393f2b4
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

To spice up your inbox with colors and themes, check out the Themes tab
under Settings.
       Customize Gmail =BB &amp;lt;https://mail.google.com/mail/#settings/themes&amp;gt;

Enjoy!

- The Gmail Team
[image: Themes thumbnails]

Please note that Themes are not available if you're using Internet Explorer
6.0. To take advantage of the latest Gmail features, please upgrade to a
fully supported
browser&amp;lt;http://support.google.com/mail/bin/answer.py?answer=3D6557&amp;amp;hl=3Den&amp;amp;=
utm_source=3Dwel-eml&amp;amp;utm_medium=3Deml&amp;amp;utm_campaign=3Den&amp;gt;
..

--e0cb4e385592f8025004c393f2b4
Content-Type: text/html; charset=ISO-8859-1

more? y/[n]: y

&amp;lt;html&amp;gt;
&amp;lt;font face="Arial, Helvetica, sans-serif"&amp;gt;
&amp;lt;p&amp;gt;To spice up your inbox with colors and themes, check out the Themes tab
under Settings.&amp;lt;/p&amp;gt;

&amp;lt;table cellpadding="0" cellspacing="0"&amp;gt;
  &amp;lt;col style="width: 1px;"/&amp;gt;
  &amp;lt;col/&amp;gt;
  &amp;lt;col style="width: 1px;"/&amp;gt;
  &amp;lt;tr&amp;gt;
    &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;td height="1px" style="background-color: #ddd"&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;
  &amp;lt;/tr&amp;gt;
  &amp;lt;tr&amp;gt;
    &amp;lt;td style="background-color: #ddd"&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;td background="https://mail.google.com/mail/images/welcome-button-background.png"
        style="background-color: #ddd; background-repeat: repeat-x;
            padding: 10px; font-size: larger"&amp;gt;
          &amp;lt;a href="https://mail.google.com/mail/#settings/themes"
            style="font-weight: bold; color: #000; text-decoration: none;
            display: block;"&amp;gt;
      Customize Gmail &amp;amp;#187;&amp;lt;/a&amp;gt;
    &amp;lt;/td&amp;gt;
    &amp;lt;td style="ba
more? y/[n]: y
ckground-color: #ddd"&amp;gt;&amp;lt;/td&amp;gt;
  &amp;lt;/tr&amp;gt;
 &amp;lt;tr&amp;gt;
    &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;td height="1px" style="background-color: #ddd"&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;
  &amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;

&amp;lt;p&amp;gt;Enjoy!&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;- The Gmail Team&amp;lt;/p&amp;gt;

&amp;lt;img width="398" height="256" src="https://mail.google.com/mail/images/gmail_themes_2.png" alt="Themes thumbnails" /&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;font size="-2" color="#999"&amp;gt;Please note that Themes are not available if
you're using Internet Explorer 6.0. To take advantage of the latest Gmail
features, please
&amp;lt;a href="http://support.google.com/mail/bin/answer.py?answer=6557&amp;amp;hl=en&amp;amp;utm_source=wel-eml&amp;amp;utm_medium=eml&amp;amp;utm_campaign=en"&amp;gt;&amp;lt;font color="#999"&amp;gt;
upgrade to a fully supported browser&amp;lt;/font&amp;gt;&amp;lt;/a&amp;gt;.&amp;lt;/font&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;/font&amp;gt;
&amp;lt;/html&amp;gt;

--e0cb4e385592f8025004c393f2b4--
.

more? y/[n]: 
&amp;gt; QUIT
+OK Farewell.

more? y/[n]: 
&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yet another great success! I was able to log in to the POP3 server and retrieve a message. The script in its current state is pretty flexible, but it requires a lot of work from the user. I'll make a few final tweaks to make interacting with the POP3 server a little easier: if the user starts a message to the server with a "!" it will be stripped out, but the script will read in data from the server until it gets to a period on a line by itself -- in other words, for commands with long responses. No "!" and the script will read in a single line, looking for the \r\n characters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;

&lt;span class="n"&gt;hostname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pop.gmail.com&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_default_context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_until&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eom&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# read into the buffer at least once
&lt;/span&gt;    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# continue reading until end of message
&lt;/span&gt;    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eom&lt;/span&gt;&lt;span class="p"&gt;):]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;eom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# return incoming bytes decoded to a string
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_single_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;read_until&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_muli_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;read_until&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_connection&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;995&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap_socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;server_hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;version&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;read_single_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# empty msg will close connection
&lt;/span&gt;        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
                &lt;span class="nb"&gt;long&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nb"&gt;long&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
            &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;long&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;read_muli_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;read_single_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>python</category>
      <category>sockets</category>
      <category>email</category>
      <category>pop</category>
    </item>
  </channel>
</rss>
