Skip to content

Welcome to The Zen of Typing! The only place you can improve your typing speed and brush up on some programming principles at the same time...

Notifications You must be signed in to change notification settings

loosenthedark/zen-of-typing

Repository files navigation

CI logo

The Zen of Typing

in-game screenshot of deployment terminal

The Zen of Typing is a Python terminal project whose primary purpose is to enable users to practice and improve their touch typing skills.

Secondarily, it serves to reinforce various (mainly Python-related) programming principles and aphorisms through the use of carefully-selected practice texts and extracts.

Users can customise their experience by choosing from a range of options before the game itself gets underway. Once all necessary pre-game instructions have been displayed and the target text is loaded, the user's performance is monitored as they attempt to replicate each line of text. As soon as they finish and hit Enter, they receive feedback in the form of a breakdown of their typing speed and accuracy. They may then choose to either restart the game or quit (and exit the application).

How to play

click to view

The Zen of Typing is loosely modelled on classic typing programmes such as 'Mavis Beacon Teaches Typing!', which the developer was known to spend countless hours practicing throughout his misspent youth.

Mavis Beacon game cover

The title is also a play on 'The Zen of Python', Pythoneer Tim Peters' list of fundamental commandments for the then-nascent programming language, which was first issued in 1999 and has since come to be seen as something of a cornerstone document.

To begin, a welcome message is communicated on the start screen and the user is asked if they would like to warm up by tackling a practice text (which is subsequently revealed to be Tom Cargill's humorous observation now known as the 'ninety-ninety rule').

How to play screenshot 1

Following this optional practice session - which they can take as many times as they wish - the user is given a multiple-choice menu of target texts, from which they must choose one by using the Up, Down and Enter keys on their keyboard. There are six texts in all, each of which is denoted by a slightly cryptic title/acronym. If the user finds that they are struggling to decide on a text, they may opt to effectively 'roll the dice' by asking the computer to pick one at random for them.

How to play screenshot 2

Once a text has been chosen, a subsequent menu similarly asks the listener to choose from a range of options, this time corresponding to the number of lines they wish to type. The list is once again navigated using the Up, Down and Enter keys.

How to play screenshot 3

Having selected both a text and the number of lines to be typed, the user is next asked if they know the secret password. This time they must provide an answer by inputting either 'Y' or 'N' on their keyboard.

How to play screenshot 4

  • If they don't know it, a summary of their choices is displayed and the target text is outputted in italics. A bold yellow "Off you go!!!" message signals that the game is underway and they must begin the typing task.

How to play screenshot 5

  • If, on the other hand, they do know the secret password (and indicate so by pressing 'Y'), they are prompted to enter it as an input string.

    • If the password they enter happens to be incorrect, they are alerted to this fact by a bold red feedback message, after which the password functionality is discarded and the game begins in the usual fashion (see above)

    How to play screenshot 6

    • If they enter a correct password, meanwhile, they unlock a bonus submenu offering the chance to acticate the 'Beast Mode' feature (explained in more detail below).

    How to play screenshot 7

    How to play screenshot 8

Features

Existing features:

click to view

ASCII art typewriter

  • Python-centric ASCII art hero image and colour scheme

    click to view

    The prevalent blue and yellow design palette both draws the user's attention and reinforces the fact that this is very much a Python application. Elsewhere, semantic text feedback is displayed in a familiar and intuitive fashion, e.g. error messages in red, success alerts in green. While many terminal projects can look drab and monotone, it was the developer's intention that The Zen of Typing should be anything but.

    Features screenshot 1

  • Immersive sequential flow of multiple-choice menus and questions (enabled c/o the PyInquirer module)

    click to view

    From a UX standpoint, the closed-ended nature of almost all of the questions with which the user is presented minimises the risk of error and all but eliminates the possibility of invalid user input. This saves time (for both developer and user), while also delivering a neat and concise pre-game interface.

  • Warm-up/Practice option

    click to view

    Not everyone is a super-fast expert typist. Similarly, not everyone produces their finest work under pressure. Bearing this in mind, The Zen of Typing allows users to practice their typing in a relaxed fashion without having to worry about performance metrics (the practice mode is not 'recorded', i.e. no speed/accuracy calculations are made). They may then progress to the stricter in-game conditions whenever they feel ready.

    Features screenshot 2

  • Randomised text selection fallback option

    click to view

    Hick's Law states that "the time it takes to make a decision increases with the number and complexity of choices". If, therefore, the user feels somewhat overwhelmed at having to choose between the six available target texts, they can simply ask the random module to help lighten their cognitive load by deciding for them.

    Features screenshot 3

  • Programming-themed target text content

    click to view

    Five of the six available target texts are directly related to computer programming, with a strong Python emphasis. While it would arguably have been simpler to work with generic/filler content, this way the Zen of Typing user stands to kill two birds with one stone (so to speak) by rounding out their coding knowledge as they're working on their typing speed.

    Features screenshot 4

  • API integration

    click to view

    One of the five programming-related target texts mentioned above is actually a dynamically-generated random list of responses from an end-point associated with the pyjokes ("jokes as a service") API.

    pyjokes logo

  • Gamification

    click to view

    One surefire way to drive user engagement is to harness the principles of operant conditioning when designing an interactive application. The Zen of Typing adheres to this objective on at least two fronts:

    • The user is provided with instant feedback in the form of a results breakdown, consisting of overall time taken, accuracy and average speed (in words typed per minute). In most cases, this alone should be enough of a hook to encourage them to keep playing in the hope of improving on their current personal best score(s)

    Features screenshot 5

    • The secret password/'Beast Mode' functionality is initially alluded to in passing, but quickly becomes a central aspect of the game. Crucially, the user is never directly informed as to how and when the next character of this password will be revealed, so they are kept guessing (and wanting more) to a large extent.

    Features screenshot 6

  • Input validation and error-checking

    click to view

    The one open-ended question demanding user input is the secret password prompt. This is handled in a straightforward binary fashion: if the user enters anything other than the correct (case-sensitive) password, they are informed of their mistake and the game simply starts as normal. This is accomplished by using a compound if statement within the game class's main activate() method.

    Features screenshot 7

Potential future features:

click to view

ASCII art computer

  • Add dynamic 'High Score' user feedback functionality

    click to view

    Given more time, an additional UX feature I would like to have included to boost gamification is a way of storing and updating their current high score (in wpm) in memory. This could be implemented by using conditional logic (attached to a class method) and writing the high score to a project .txt file. A good example can be found in this video tutorial

  • Follow-up email feature Ask user to enter email and send them a breakdown of their typing speed/accuracy (via smtplib module)?

    click to view

    Another way to keep the user hooked and ensure they return to the application would be if they received a summary breakdown of their performance (average typing speed, accuracy, high score etc.) after they have exited the programme. This would probably be a good use case for the smtplib module

  • Social media integration

    click to view

    Allowing users to share their new high score (see above) etc. via social media would be a great way to publicise the app and start growing a community of TZOT users. The actively maintained twython module looks like it would be ideal for this purpose, Twitter being the channel that arguably lends itself best to this type of functionality. There's even scope for uploading an image as part of a status update, which would be useful for sharing in-game screenshots with the world at large.

  • Real-time user feedback

    click to view

    At present, users are only able to get an indication of how quickly and accurately they are typing after they have completed a typing task (i.e. as soon as they press Enter at the end of a target text, they are given a results breakdown). A more dynamic means of providing user feedback would be to have a running timer situated somewhere in the UI, as well as displaying a 'live' words-per-minute calculation. Going further, incorrectly-typed text could also be highlighted in real time so that the user would be able to go back and correct mistake(s) (cf. this example). On reflection, it's likely that this functionality would have required quite extensive refactoring, and so a decision was made to leave it out of this initial app version.

  • Add margin/padding to mock terminal output

    click to view

    From a cosmetic standpoint, terminal text by default is not particularly pleasing to the eye. Part of the reason for this is the lack of layout and spacing options, which can often lead to things looking quite bunched and difficult to read. With this in mind, it would be nice to be able to add some extra spacing between the left and right borders of the mock terminal and the text output (chiefly the target text and/or user input) in order to improve readability and overall appearance (cf. this blog post).

  • Bind secret password reveal functionality not just to typing speed, but also to accuracy

    click to view

    At the time of writing, the user is rewarded via the application's incremental secret password reveal functionality based solely on typing speed. More specifically, they are shown the first character of this password when they record a speed of 20 words per minute, the second when they reach 30 wpm, the third at 40 wpm and the fourth and final character once they achieve a speed of 50 wpm. However, this happens irrespective of typing accuracy - theoretically, a user could therefore speed-type gibberish (i.e. record an extremely low accuracy rate) and still manage to unlock the password and access Beast Mode. This could be prevented using more sophisticated and nuanced conditional logic, and is something the developer intends to implement in future revisions of the app.

Technologies Used

Language(s):

click to view
  • Python 3.9.2: used to anchor the project and direct all application behaviour
  • JavaScript: used to provide the start script needed to run the Code Institute mock terminal in the browser
  • HTML used to construct the elements involved in building the mock terminal in the browser

Frameworks/Libraries, APIs, Programmes and Tools:

click to view
  • Python modules/packages:

    • Standard library imports:

      • python-future: used to ensure a fully Python 2/3-compatible codebase
      • random: used to implement pseudo-random number generation
      • sys: used to provide various functions and variables that are used to manipulate different parts of the Python runtime environment
      • textwrap: used for wrapping and formatting of plain text throughout the project (made necessary due to the width and height constraints of the browser mock terminal)
      • time: used to provide ad hoc stopwatch-like functionality when calculating and recording user typing speed
    • Third-party imports:

      • PyInquirer: used to provide a collection of common interactive command line user interfaces, e.g. for compiling multiple-choice questions and managing in-app hierarchical prompts in an intuitive and efficient manner
      • pyjokes: used to supply the project with a randomly-assembled feed of one-line programming jokes, which is then repurposed into one of the app's target texts availabel to the user
      • Prompt Toolkit: cross-platform foundational library on top of which PyInquirer (see above) is built
  • Visual Studio Code: used as the online IDE for the project

  • Git: used to handle version control throughout the project's evolution

  • GitHub: used to compile and remotely store the project's codebase following successive local commits initiated from the command line

  • Heroku: used to deploy the site and aid workflow in line with serverless continuous deployment best practices

  • pyjokes API: used to request and compile lists of programming jokes as needed (via the module's get_jokes function)

  • Valentin Bryukhanov's PEP8 online checker was used to validate the project's Python code, in line with best practice.

  • Ezgif image converter: used to convert the Python logo used in the creation of a project favicon from .svg to .png format

  • PicResize: used to crop and resize images

  • Editor.md: used to format project Markdown in line with best practices

Data Model

click to view

A TypingText class has been used as the main application model.

data model screenshot

This class's __init__ state initialisation method creates properties to store the following app-related information:

  • game mode: By default, the class's beast property is set to False. What this means is that the game's Beast Mode (which involves the user having to type target text lines backwards) has not been enabled, and so the normal mode of standard text display is in effect.
  • (boolean) game state flags pertaining to each of the following:
    • whether or not the game has started
    • whether or not the game has finished
    • whether or not the game is currently running
  • string values (initially set to empty strings) corresponding to the self-explanatory properties of text_typed and text_to_be_typed
  • user performance- and results-related properties (all of which are initially set to 0):
    • start_time
    • total_time
    • typing_accuracy
    • wpm (words per minute)

The class also has three game-centric methods - the names of which are again self-explanatory - that are used to coordinate various aspects of functionality:

  • activate()
  • game_restart()
  • calculate_results()

It was not deemed necessary to create any instances of this class, as the game functionality doesn't really call for it.

Testing

The application was rigorously tested throughout its development life cycle. This process ranged from manual testing (e.g. by deliberately entering an incorrect password when prompted) through to automated validator testing. As always, numerous bugs were identified at various stages - some of which have since been resolved, while others have proven to be more persistent and will have to be tackled at some point in the future.

Bugs:

click to view

Solved Bugs:

Bug: ValueError showing in deployment terminal

An example of a bug (one of many) that the developer managed to rectify is the ValeError shown in the screenshot above. Such error messages were invariably returned when an inappropriate value was being passed as an argument to a function, and required careful and continuous debugging.

Remaining Bugs:

Flashing/Blinking terminal text, e.g. when asking the user if they wish to play the game again, was a feature that failed to launch - for reasons that aren't immediately evident to the developer. It's likely to be related to ANSI SGR behaviour and how this is rendered in the browser. Whatever the cause(s) of this bug, unfortunately the examples of 'blinking' output seen here could not be replicated in TZoT for the time being.

One rather obvious blind spot in the game's design is that it is possible to completely cheat and record an impossibly high wpm score by simply copying and pasting the target text as it is printed to the screen into the terminal as user input. Going forward it would obviously be a good idea to mitigate against this type of user behaviour - though it would require some further exploration, e.g. to find a module tailored to this purpose.

Finally, one more design flaw within the application is the fact that the TypingText class's calculate_results method only allows for direct character-by-character comparison when calculating user accuracy. Thus, if the user mistakenly types a single extra character somewhere, all subsequent characters in that user input string are likely to be deemed 'mistakes' - even if they happen to be completely accurate in terms of what the user is attempting to type at that particular moment in time. This problem is perhaps best illustrated using an in-game screenshot:

Bug: typing accuracy screenshot

Validation:

click to view

Valentin Bryukhanov's online validation tool was used to ensure that all of the project's Python source code is Pep 8-compliant. This checking was done by simply copying and pasting the contents of both the run.py file into the relevant field and clicking on Check code. Initially a number of non-compliance errors were returned; these were mostly in the form of "E501: line too long" messages. After making all necessary modifications, the Python code now passes through this validator without any problems:

run.py validation

Python validation icon

Deployment

GitHub

click to view

This project was developed in a repository built on top of the Code Institute Python Essentials template repository, thus inheriting the latter's main directory structure and starter files.

Creating the repository from the template involved following each of these steps:

  1. On GitHub.com, navigate to the main page of the template repository - in this case, this page.

Deployment screenshot 1

  1. Above the file list, click Use this template.

Deployment screenshot 2

  1. On the next screen, select the account you want to own the repository from the Owner drop-down menu.

Deployment screenshot 3

  1. Enter a Repository name, as well as an optional Description.

Deployment screenshot 4

  1. Choose a repository visibility. NB: To meet Code Institute project submission criteria, this must be set to Public.

Deployment screenshot 5

  1. Click Create repository from template.

Deployment screenshot 6

For a more detailed explanation, see 'Creating a repository from a template' (GitHub Docs)

Forking the GitHub repository

click to view

It is possible to fork this project's GitHub repository to view and/or make changes without affecting the original. This is achieved by following these steps...

NB: The steps outlined below assume that you already have Git set up on your computer - for an overview of how to download, install, and configure Git, consult the GitHub Docs

  1. Sign in to your GitHub account and locate the relevant repository.

  2. Click on Fork, located near the top right-hand corner of the repository page.

Deployment screenshot 7

  1. You will now have a copy of this project's repository in your own GitHub account.

Making a local clone

click to view

It is possible to copy the repository to your local machine so that you can fix merge conflicts, add or remove files and push larger commits without affecting the original project code. Cloning a repository pulls down a full copy of all the repo data that GitHub has at that point in time. See the GitHub Docs for further information, and below for a brief summary...

  1. Sign in to your GitHub account and locate the relevant repository.

  2. Click on the Code dropdown next to the green Gitpod button. This will reveal the Clone option.

Deployment screenshot 8

  1. In order to clone the repository using HTTPS, select HTTPS and copy the link shown (there is a copy button to the right of the URL).

Deployment screenshot 9

  1. Next, open Git Bash (see here for an overview of download options, if required).

  2. Change the current working directory on your local machine to the location where you want the cloning to be made.

  3. Type git clone into your IDE terminal followed by the URL you copied in Step 3 above, i.e.

git clone https://github.com/loosenthedark/zen-of-typing.git
  1. Press Enter.

  2. Your local clone has now been created.

See the GitHub Docs for more information on all of the above processes.

Heroku

click to view

The application is deployed on Heroku, and can be accessed using the following URL: https://zen-of-typing.herokuapp.com/

The steps involved in deploying to Heroku were as follows:

  1. Create a requirements.txt file from the command line, and populate it with a list of project dependencies:
pip freeze > requirements.txt
  1. Save, commit and push your changes to GitHub.

  2. Create a Procfile

echo web: node index.js > Procfile

NB: This file comes baked-in with the Code Institute project template repository, so can be skipped if you are using that in your own build

  1. Create an account with Heroku, selecting Python as the primary development language.

  2. Log in to your account, and in the top right-hand corner of the Dashboard click on New > Create new app

Deployment screenshot 10

  1. Enter a unique name for your app and select your region. Click on Create app.

  2. Go to Settings

Deployment screenshot 11

  1. Click on the Reveal Config Vars button in the 'Config Vars' section.

Deployment screenshot 12

  1. Enter PORT in the KEY field and 8000 in the VALUE field.

Deployment screenshot 13

  1. In the 'Buildpacks' section further down the settings page, click on Add buildpack.

Deployment screenshot 14

  1. Select python and nodejs from the menu of "officially supported buildpacks".

Deployment screenshot 15

NB: Python must be placed at the top of your app's buildpack list. You can drag and drop your buildpacks to reposition them if necessary.

  1. Go to Deploy.

Deployment screenshot 16

  1. Select GitHub in the 'Deployment method' section.

Deployment screenshot 17

  1. In the 'Connect to GitHub' section, search for the repository you wish to use, then click Connect.

Deployment screenshot 19

  1. Ensure that the project's main or master branch (depending on which is being used as the primary branch) is selected under 'Deploy a GitHub branch' in the 'Manual deploy' section.

Deployment screenshot 18

NB: If you choose to Enable Automatic Deploys, Heroku will rebuild the app every time you push a change to GitHub (which is considered best practice in most instances).

  1. After clicking on the Deploy Branch button, you should see a message confirming that "Your app was successfully deployed" followed by a View button which can be clicked to launch and view the app.

Credits

Code

Where code blocks/snippets/suggestions have been incorporated from external sources into this project's code, these have been noted through the use of comments. Beyond this, the developer made use of the following articles, workarounds and learning resources while building the site:

click to view

Content

click to view

Media

click to view
Media title/description Media format Credit Link to original media source(s)
Python icon ASCII art .txt Matthew Barber (honno) on GitHub Reddit (Python subreddit)
Python background wallpaper .png Reddit Python subreddit
Python logo used to create favicon .svg Wikipedia Wikipedia
pyjokes logo .png pyjokes Docs) pyjokes Docs
Typewriter ASCII art .jpg Pinterest) chelleline.com
Computer ASCII art .jpg Pinterest) text-mode.tumblr.com/

Acknowledgments:

  • As with my previous two projects, my number one cheerleader, product tester and source of both inspiration and sanity throughout the current build process has been my amazing partner Ana. Muito obrigado, menina ❤️
  • My mentor Tim Nelson was also on hand once more to provide invaluable guidance and encouragement. Among many other things, he helped me identify an issue with my requirements.txt file that had escaped my attention 🙌 😅

Notice

This site has been created for development purposes only.

Python logo wallpaper background