<?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>DEV Community: Milnor</title>
    <description>The latest articles on DEV Community by Milnor (@milnor).</description>
    <link>https://dev.to/milnor</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%2F1074077%2F436953f5-6e9b-4db6-b4c2-653db696f8cf.png</url>
      <title>DEV Community: Milnor</title>
      <link>https://dev.to/milnor</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/milnor"/>
    <language>en</language>
    <item>
      <title>Training a Snake to Clean my Desktop</title>
      <dc:creator>Milnor</dc:creator>
      <pubDate>Wed, 17 May 2023 18:36:39 +0000</pubDate>
      <link>https://dev.to/milnor/training-a-snake-to-clean-my-desktop-3738</link>
      <guid>https://dev.to/milnor/training-a-snake-to-clean-my-desktop-3738</guid>
      <description>&lt;h2&gt;
  
  
  The Task
&lt;/h2&gt;

&lt;p&gt;The final project in the &lt;a href="https://codingnomads.co/" rel="noopener noreferrer"&gt;Coding Nomads&lt;/a&gt; Python 101 course is to write (1) a Python script that automatically cleans your Desktop by moving all screenshots to a new folder; and (2) writing a blog post about said script.&lt;/p&gt;

&lt;p&gt;I began the project by looking at my actual Desktop and thinking about how to tailor the stated task to meet my actual needs. A minimally acceptable solution is to create a new folder and transfer all &lt;code&gt;.png&lt;/code&gt; images into it, but that would hardly make a dent in the 99 items contained in &lt;code&gt;C:\Users\MyName\Desktop&lt;/code&gt;. Therefore, my revised plan is to automatically move:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.png&lt;/code&gt;s, &lt;code&gt;.svg&lt;/code&gt;s, and &lt;code&gt;.gif&lt;/code&gt;s into a new subdirectory, &lt;code&gt;PICS&lt;/code&gt;; &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.txt&lt;/code&gt;s, &lt;code&gt;.md&lt;/code&gt;s, and &lt;code&gt;.rtf&lt;/code&gt;s into &lt;code&gt;NOTES&lt;/code&gt;; &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.pdf&lt;/code&gt;s into &lt;code&gt;PDFS&lt;/code&gt;; and &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.c&lt;/code&gt; source files into &lt;code&gt;CODE&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
Yes, I have outed myself. I am a C developer. You won't find a lick of Python on my cluttered Desktop, yet.



&lt;h2&gt;
  
  
  Setting the Path to my Desktop
&lt;/h2&gt;

&lt;p&gt;If I were coding this tool at work, the path to the Desktop would likely be set via a command line argument. However, we haven't "officially" learned to parse command line arguments with &lt;code&gt;sys.argv()&lt;/code&gt; or &lt;code&gt;argparse&lt;/code&gt; yet. Another option would be to prompt for user input, but during a lab exercise, I had a bad experience where I meant to type &lt;code&gt;C:\Users\MyName\Desktop\TestFolder&lt;/code&gt;, but I missed the &lt;code&gt;\&lt;/code&gt; key and hit &lt;code&gt;Enter&lt;/code&gt; early, mistakenly running faulty work-in-progress code against my actual Desktop! (Fortunately, that script crashed after moving a single file to where I didn't want it). In the interest of safety, I will hardcode the path thus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;desktop = pathlib.Path(r"C:\Users\MyName\Desktop\TestFolder")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only after I've tested the script against &lt;code&gt;TestDir&lt;/code&gt; will I shorten the path to run things against my Desktop for real. &lt;/p&gt;

&lt;p&gt;Giving credit where credit is due, &lt;a href="https://stackoverflow.com/questions/1347791/unicode-error-unicodeescape-codec-cant-decode-bytes-cannot-open-text-file" rel="noopener noreferrer"&gt;Stack Overflow&lt;/a&gt; straightened me out when my initial code was wrong. The Windows path separator &lt;code&gt;\&lt;/code&gt; easily collides with Unicode escape sequences, so I added &lt;code&gt;r&lt;/code&gt; to create a raw string, slightly easier than escaping each path separator.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the New Directories
&lt;/h2&gt;

&lt;p&gt;Since I want to create a series of new directories, not just one, I iterated through a list of names, joining them to the &lt;code&gt;desktop&lt;/code&gt; path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for sub_dir in ["CODE", "NOTES", "PDFS", "PICS"]:
    new_dir = desktop.joinpath(sub_dir)
    new_dir.mkdir(exist_ok=True)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;exist_ok&lt;/code&gt; argument should make testing less tedious, since the script won't error out if run in succession without deleting the new folders in between.&lt;/p&gt;

&lt;h2&gt;
  
  
  Identifying and Relocating Files
&lt;/h2&gt;

&lt;p&gt;A hefty for loop did all the heavy lifting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Filter for screenshots only
for each in desktop.iterdir():
    if not each.is_file():
        # Skip directories
        continue

    extension = each.suffix.lower()

    # Create a new path for each file
    if extension in [".c", ".h", ".py"]:
        # put it in CODE
        new_path = desktop / "CODE" / each.name

    elif extension in [".md", ".rtf", ".txt"]:
        # put it in NOTES
        new_path = desktop / "NOTES" / each.name

    elif extension == ".pdf":
        # put it in PDFS
        new_path = desktop / "PDFS" / each.name

    elif extension in [".bmp", ".gif", ".jpg", ".jpeg", ".svg", ".png"]:
        # put it in PICS
        new_path = desktop / "PICS" / each.name

    else:
        continue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, I iterated through every file on the Desktop using &lt;code&gt;iterdir()&lt;/code&gt;. Second, to recognize file types in a case-insensitive fashion, I converted the suffix of each file to lowercase and tested whether it was found in a list of file extensions belonging to the same category. Third, I set a &lt;code&gt;new_path&lt;/code&gt; variable with the future location of the file. As a convenience, &lt;code&gt;pathlib.Path&lt;/code&gt; supports building paths using the &lt;code&gt;/&lt;/code&gt; operator; I find that more readable than the &lt;code&gt;joinpath()&lt;/code&gt; method when you have multiple pieces to string together.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;files_moved = 0

....

# Move the screenshot there
print(f"[!] Moving {each} to {new_path}...")
each.rename(new_path)
files_moved += 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, &lt;code&gt;each&lt;/code&gt; file from the for loop was moved to &lt;code&gt;new_path&lt;/code&gt; using the &lt;code&gt;rename()&lt;/code&gt; method. For my own edification, I added a &lt;code&gt;files_moved&lt;/code&gt; variable to quantify the work completed by the automation script.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running it...
&lt;/h2&gt;

&lt;p&gt;When I changed the path from the test directory to my actual Desktop, the script proudly reported &lt;code&gt;[+] Successfully moved 41 files!&lt;/code&gt;. This was nice and all, but a quick visual inspection told me that the PDFs stayed put. Notice that unlike the other categories of files, there is only one valid file extension for a PDF. The initial version of my code had a silly logic bug that was syntactically valid: &lt;code&gt;elif extension == [".pdf"]:&lt;/code&gt;. After quickly fixing that and re-running the script, 16 additional files were relocated.&lt;/p&gt;

&lt;p&gt;Now, with my Desktop in a semblance of order, I can tackle individual subdirectories at my leisure and delete any files that do not spark joy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flp0n6xgyylkefevnnk1f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flp0n6xgyylkefevnnk1f.jpg" alt="Custom KonMari meme that suggests vacation photos spark joy but credit card statements do not"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Complete Code Listing
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Write a script that moves all files with the .png extension
# from one folder to another
""" Clean up my Desktop Automagically """

import pathlib

# Find the path to my Desktop
desktop = pathlib.Path(r"C:\Users\MyName\Desktop")

# Create a new folder
for sub_dir in ["CODE", "NOTES", "PDFS", "PICS"]:
    new_dir = desktop.joinpath(sub_dir)
    new_dir.mkdir(exist_ok=True)

files_moved = 0

# Filter for screenshots only
for each in desktop.iterdir():
    if not each.is_file():
        # Skip directories
        continue

    extension = each.suffix.lower()

    # Create a new path for each file
    if extension in [".c", ".h", ".py"]:
        # put it in CODE
        new_path = desktop / "CODE" / each.name

    elif extension in [".md", ".rtf", ".txt"]:
        # put it in NOTES
        new_path = desktop / "NOTES" / each.name

    elif extension == ".pdf":
        # put it in PDFS
        new_path = desktop / "PDFS" / each.name

    elif extension in [".bmp", ".gif", ".jpg", ".jpeg", ".svg", ".png"]:
        # put it in PICS
        new_path = desktop / "PICS" / each.name

    else:
        continue

    # Move the screenshot there
    print(f"[!] Moving {each} to {new_path}...")
    each.rename(new_path)
    files_moved += 1

if files_moved &amp;gt; 0:
    print(f"[+] Successfully moved {files_moved} files!")

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

&lt;/div&gt;



</description>
      <category>python</category>
      <category>beginners</category>
      <category>automation</category>
    </item>
    <item>
      <title>Writing Hangman with Coding Nomads</title>
      <dc:creator>Milnor</dc:creator>
      <pubDate>Mon, 15 May 2023 21:27:24 +0000</pubDate>
      <link>https://dev.to/milnor/writing-hangman-with-coding-nomads-4ap4</link>
      <guid>https://dev.to/milnor/writing-hangman-with-coding-nomads-4ap4</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Recently I started the Python Bootcamp offered by &lt;a href="https://codingnomads.co/"&gt;Coding Nomads&lt;/a&gt;, despite being a professional developer already. I originally learned Python in a haphazard manner: Googling "how to X in python", then pasting together useful snippets from Stack Overflow. Now it's back to the basics as I re-learn how to use the language in a more idiomatic fashion under the guidance of a mentor. A complete code listing of my Hangman implementation is pasted at the bottom, but first I'll comment on design decisions, challenges, etc. in select snippets.&lt;/p&gt;

&lt;p&gt;I grew up playing "Hangman" using paper-and-pencil. If the rules are unfamiliar to you, try the game's &lt;a href="https://en.wikipedia.org/wiki/Hangman_(game)"&gt;Wikipedia page&lt;/a&gt;. In a nutshell, you have a finite number of guesses to come up with all the letters in a mystery word. With each correct guess, you are shown all occurrences of a letter within the word. With each wrong guess, body parts are added to a simple sketch of you hanging from a noose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Displaying the Word
&lt;/h2&gt;

&lt;p&gt;Initially, I was tracking a &lt;code&gt;secret_word&lt;/code&gt; string variable along with two lists (&lt;code&gt;right_letters&lt;/code&gt; and &lt;code&gt;wrong_letters&lt;/code&gt;) guessed by the player. At first I just printed the word (including only the correctly guessed letters) to the screen; e.g. &lt;code&gt;_ e _ _ _&lt;/code&gt;. Later I decided to save this representation of the word to a variable &lt;code&gt;word_in_progress&lt;/code&gt;, since winning the game could be detected when the string no longer contained any underscores.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;secret_word = "crumpet"

right_letters = []
wrong_letters = []

    # Display the word as a sequence of blanks, e.g. "_ _ _ _ _" for "hello"
    # When they find a correct character, display the blank with the word
    #   filled in, e.g.: "_ e _ _ _" if they guessed "e" from "hello"
    word_in_progress = ""
    for each in secret_word:
        if each in right_letters:
            word_in_progress += each + " "
        else:
            word_in_progress += "_ "
    print(word_in_progress)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Embellishment: Adding ASCII Art
&lt;/h2&gt;

&lt;p&gt;What CLI game would be complete without &lt;a href="https://en.wikipedia.org/wiki/ASCII_art"&gt;ASCII art&lt;/a&gt; graphics?&lt;br&gt;
I created a multi-line string variable &lt;code&gt;wrong_6&lt;/code&gt; to represent losing the game and being hanged by the neck until dead. Then I worked backwards with &lt;code&gt;wrong_5&lt;/code&gt; (one leg missing) through &lt;code&gt;wrong_0&lt;/code&gt; (an empty gallows).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wrong_6 = """
========
 ||  |
 ||  O
 || /|\
 || / \
 ||
===========
"""
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I ran the game; however, something looked off. I soon remembered that &lt;code&gt;\&lt;/code&gt; is often an escape character in programming languages, so I corrected the limbs on the right side of the drawing to look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wrong_6 = """
========
 ||  |
 ||  O
 || /|\\
 || / \\
 ||
===========
"""
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Linting Headaches
&lt;/h2&gt;

&lt;p&gt;New programmers may be unfamiliar with the term &lt;em&gt;linting&lt;/em&gt;. It refers to running your code through a static analysis tool (called a &lt;em&gt;linter&lt;/em&gt;) that warns you when you don't conform to best practices for the language you are writing. In the case of Python, for instance, &lt;a href="https://peps.python.org/pep-0008/"&gt;PEP-8&lt;/a&gt; is the authoritative standard on best practices and &lt;a href="https://pypi.org/project/pylint/"&gt;pylint&lt;/a&gt; one of the popular linters. &lt;a href="https://pypi.org/project/black/"&gt;Black&lt;/a&gt; is also a great linter that should be on your radar, though I don't discuss it further here.&lt;/p&gt;

&lt;p&gt;At my job as a developer, if I write code that doesn't pass &lt;code&gt;pylint&lt;/code&gt; (or another language-specific linter, as appropriate), my commit will get rejected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Naming Conventions
&lt;/h3&gt;

&lt;p&gt;I ran &lt;code&gt;python -m pylint hangman.py&lt;/code&gt; and received several warnings about naming conventions. (Note: If you are a Linux developer, assuming &lt;code&gt;pylint&lt;/code&gt; is already installed, you should be able to run it more simply: &lt;code&gt;pylint hangman.py&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hangman.py:68:0: C0103: Constant name "wrong_4" doesn't conform to UPPER_CASE naming style (invalid-name)
hangman.py:78:0: C0103: Constant name "wrong_5" doesn't conform to UPPER_CASE naming style (invalid-name)
hangman.py:88:0: C0103: Constant name "wrong_6" doesn't conform to UPPER_CASE naming style (invalid-name)
hangman.py:109:4: C0103: Constant name "word_in_progress" doesn't conform to UPPER_CASE naming style (invalid-name)
hangman.py:155:8: C0103: Constant name "your_letter" doesn't conform to UPPER_CASE naming style (invalid-name)
hangman.py:160:16: C0103: Constant name "your_letter" doesn't conform to UPPER_CASE naming style (invalid-name)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since I am primarily a C developer and learning to write Python like an adult is relatively new, these warnings suggest to me: "I, your great and mighty linter, believe that your global variables are all constants, kind of like a &lt;code&gt;#define PI 3.14&lt;/code&gt; in C, and ought to be written in ALL_CAPS rather than snake_case." However, since I'm still early on in the Coding Nomads bootcamp and don't know the best practices, I decided to kick the can down the road.&lt;/p&gt;

&lt;p&gt;Instead of refactoring to avoid global variables or painstakingly rename them all, a quick Google search told me that I could disable the warning with &lt;code&gt;# pylint: disable=invalid-name&lt;/code&gt;. 😎&lt;/p&gt;

&lt;h3&gt;
  
  
  Long Lines
&lt;/h3&gt;

&lt;p&gt;There was another linting error that I decided &lt;em&gt;did&lt;/em&gt; need fixing. One line of the code was very long:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if your_letter in right_letters or your_letter in wrong_letters or not your_letter.isalpha():
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I didn't trust the user to guess a letter that hadn't already been guessed. In fact, I don't trust the user to even guess a "letter" that is even alphanumeric, let alone alphabetic. So, I wrapped the user input in a &lt;code&gt;while&lt;/code&gt; loop that &lt;code&gt;continue&lt;/code&gt;s &lt;em&gt;ad infinitum&lt;/em&gt; until they get it right. (Note: If you are a new developer and haven't learned to sanitize your inputs, you really ought to read the &lt;a href="https://imgs.xkcd.com/comics/exploits_of_a_mom.png"&gt;Bobby Tables&lt;/a&gt; cartoon by XKCD.)&lt;/p&gt;

&lt;p&gt;Pardon the rabbit trail about why that long line was necessary. The question was how to shorten it so that &lt;code&gt;pylint&lt;/code&gt; would accept my code. Python is very sensitive to whitespace being just so, so when I split the long line into two, it complained about how I did it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;            if your_letter in right_letters or your_letter in wrong_letters or not
            your_letter.isalpha():
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hangman.py:158:83: E0001: Parsing failed: 'invalid syntax (&amp;lt;unknown&amp;gt;, line 158)' (syntax-error)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A little more Googling combined with trial-and-error determined that this would work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;            if your_letter in right_letters or your_letter in wrong_letters or not \
               your_letter.isalpha():
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Randomizing the Secret Word (Potential Spoiler)
&lt;/h2&gt;

&lt;p&gt;The course suggested this optional extension to make the game more interesting: "If you want to practice your online research skills, then explore some possible ways to get a word into your game that you don't know yourself. That would make it a lot more fun to play the game by yourself."&lt;/p&gt;

&lt;p&gt;Initially, to test the script during development, I hard-coded an arbitrary "secret" word to guess:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Hard-code a word that needs to be guessed in the script
secret_word = "crumpet"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where could I go to get a large pool of words? If I were working in a Linux environment, there would likely be an entire dictionary available within &lt;code&gt;/usr/share/dict/&lt;/code&gt;. Alas, my Linux VM (virtual machine) was freezing for unknown reasons, so I began this project in the &lt;em&gt;terra incognita&lt;/em&gt; of a Windows 11 environment.&lt;/p&gt;

&lt;p&gt;Our good friend Google led me to a question on Stack Overflow about writing a &lt;a href="https://stackoverflow.com/questions/18834636/random-word-generator-python"&gt;random word generator in Python&lt;/a&gt;. The accepted answer was written for Python2, but just below it was a Python3 alternative using &lt;code&gt;urllib&lt;/code&gt; from the standard library. It pointed to a &lt;a href="http://svnweb.freebsd.org/csrg/share/dict/words?view=co&amp;amp;content-type=text/plain"&gt;website that was down&lt;/a&gt; at the time I tried it -- though as of writing this blog post, it has come back up -- so I swapped in the &lt;a href="https://www.mit.edu/~ecprice/wordlist.10000"&gt;URL from the Python2 example&lt;/a&gt; and everything worked beautifully.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import random
import urllib.request

word_url = "https://www.mit.edu/~ecprice/wordlist.10000"
response = urllib.request.urlopen(word_url)
long_txt = response.read().decode()
words = long_txt.splitlines()
secret_word = random.choice(words)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Code Listing
&lt;/h2&gt;

&lt;p&gt;The complete code differs slightly from the snippets above due to changes under version control (the original sits within a private repo on GitHub) as well as pulling out just the parts relevant to a topic of discussion.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;""" The Game of Hangman """
# pylint: disable=invalid-name

import random
import sys
import urllib.request

# adapted from https://stackoverflow.com/questions/18834636/random-word-generator-python
word_url = "https://www.mit.edu/~ecprice/wordlist.10000"
response = urllib.request.urlopen(word_url)
long_txt = response.read().decode()
words = long_txt.splitlines()
secret_word = random.choice(words)

right_letters = []
wrong_letters = []

# Create a counter for how many tries a user has
wrong = 0   # number of incorrect guesses, up to 6

wrong_0 = """
========
 ||  |
 ||  
 || 
 || 
 ||
===========
"""

wrong_1 = """
========
 ||  |
 ||  O
 || 
 || 
 ||
===========
"""

wrong_2 = """
========
 ||  |
 ||  O
 ||  |
 || 
 ||
===========
"""

wrong_3 = """
========
 ||  |
 ||  O
 || /|
 || 
 ||
===========
"""

wrong_4 = """
========
 ||  |
 ||  O
 || /|\\
 || 
 ||
===========
"""

wrong_5 = """
========
 ||  |
 ||  O
 || /|\\
 ||   \\
 ||
===========
"""

wrong_6 = """
========
 ||  |
 ||  O
 || /|\\
 || / \\
 ||
===========
"""

# Print an explanation to the user
print("  =======================")
print(" / Welcome to Hangman! /")
print("======================= ")

# Keep asking them for their guess until they won or lost
while wrong &amp;lt;= 6:
    # Display the word as a sequence of blanks, e.g. "_ _ _ _ _" for "hello"
    # When they find a correct character, display the blank with the word
    #   filled in, e.g.: "_ e _ _ _" if they guessed "e" from "hello"
    word_in_progress = ""
    for each in secret_word:
        if each in right_letters:
            word_in_progress += each + " "
        else:
            word_in_progress += "_ "
    print(word_in_progress)

    # My embellishments
    if wrong == 0:
        print(wrong_0)
    elif wrong == 1:
        print(wrong_2)
    elif wrong == 2:
        print(wrong_1)
    elif wrong == 3:
        print(wrong_3)
    elif wrong == 4:
        print(wrong_4)
    elif wrong == 5:
        print(wrong_5)
    elif wrong == 6:
        print(wrong_6)

    print("Correct Guesses: ", end=' ')
    for each in right_letters:
        print(each, end=' ')
    print("")

    print("Incorrect Guesses: ", end=' ')
    for each in wrong_letters:
        print(each, end=' ')
    print("")

    # Ask for user input
    if wrong == 6:
        # Display a losing message and quit the game if they don't make it
        print("Sorry, you lose.")
        sys.exit()
    elif "_" not in word_in_progress:
        # Display a winning message and the full word if they win
        print("Congrats, you win.")
        sys.exit()
    else:
        # Allow only single-character alphabetic input
        print("\n\n")
        your_letter = None
        while your_letter is None:
            your_letter = input("Guess a letter: ").lower()
            if your_letter in right_letters or your_letter in wrong_letters or not \
               your_letter.isalpha():
                your_letter = None
                continue
            if your_letter in secret_word:
                print("Good guess!")
                right_letters.append(your_letter)
            else:
                print("Nope!")
                wrong_letters.append(your_letter)
                wrong += 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  About Me
&lt;/h2&gt;

&lt;p&gt;I get paid to code, but also put much effort into drawing silly cover art in MS Paint to adorn software user manuals and the occasional blog post.&lt;/p&gt;

</description>
      <category>python</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
