Codecademy Python terminal game – Epsilon the cat

Motivation

I got to look after a cat named Epsilon for close to 10 months while her owner went for study exchange.

After returning her to the owner, I kinda miss her.

I miss that whenever I said her name “Epsilon”, she knew it’s food time and ran from where-ever she’s sleeping to the kitchen.

While following Codecademy Computer Science curriculum, I am to create personal project in Python terminal program. I take this chance to create a little game dedicated to Epsilon.

game screenshot

Users’ stories

  • User know that the game starts, by seeing a board, a narration, a game control instruction
  • Player can move Epsilon to a direction when user hits a keystroke
    • the direction keystrokes are w, a, s, d or arrow keys, because it’s intuitive for everyone playing games
  • When player moves Epsilon to Food, player wins the game
  • Player can quit the game early by press the ‘q’ keyboard
  • When player types any others keys apart from the our game’ controller allowed key, player sees a note. Player also sees that Epsilon stay at the same spot on the board

The game

You can give the game a whirl by cloning this GitHub repo.

Program flow diagram

Development notes

Character encoding

I chose to use 🐈 , instead of 🐈‍⬛ .

🐈‍⬛  seems to take more encoding bits, and break the Board’s cell on some terminal’s environment. This only happens to some terminal environment, for example using Visual Studio Code’s terminal running on zsh , but not reproducible with Mac’s Terminal

because it looks better (more noticeable compared to the black cat 🐈‍⬛) on dark-themed Terminal, which should be the default for the majority of developers

left: 🐈‍⬛ rendered on VSC’s terminal. right: on Mac’s native terminal

screenshot for black cat emoji when rendered on VSC’s terminal

screenshot when rendered on Mac's terminal

Player sees the game responds immediately upon hitting the keystroke

At first, I used Python’s native input to receive player’s control, as input is a ‘requirement’ in this project.

Add at least one interactive feature using input()

I soon realised it’s not sensible that player have to type Enter every time to move Epsilon. The game interactivity should be as instantly as the moment they hit a key.

Therefore, I found the getKey module to serve this job.

And, the bonus is player can type arrow keys to move Epsilon around.

Generalise into BoardPiece

In the 1st prototype, Epsilon, food, and their positions on the game board are all distinct variables (see commit 7a6b029 “Initial commit”).

I decided to create a general BoardPiece that Epsilon and Food inherit from.

Because, first reason, I noticed they share a similar attribute: (x, y) co-ordinates on the game board, and emoji as graphical representation

and second reason, I want to extend the game to this user story

On difficult level, Epsilon is chased by a Needle. User needs to get Epsilon to Food before Needle catches Epsilon. Otherwise, user loses the game

Therefore, this general object allows creating Needle sub-class in the future, which share the attribute (x, y) co-ordinate on the game board, and share the methods for moving around like Epsilon

Also, it makes sense that BoardPiece and Board must associate with each other,

and to me, passing a Board object as a BoardPiece parameter is the most intuitive way to model their relation.

Testing

Unit-level testing

I expressed testing against Epsilon, Food, and Board objects on unit-level, by writing test cases to the object-definition file and executing those test cases when running the file.

This tomfoolery idea is the result of, by the time of developing this project, I was not familiar with any testing module, neither unittest or pytest.

I wrote test cases for behaviors (or methods) that are exposed to the users. For example, I wrote tests for Epsilon‘s methods to move around the game board.

Edge cases

Edge cases that pop up in my mind.

  • Can player control Epsilon with capital W, A, S, D (holding Shift + the key)
    • similarly, can player exit the game with capital Q?
  • because Epsilon and Food are placed on random on the board, what if Epsilon and Food are randomly placed on the same tile. the player will win instantly, won’t they?
    • should the code checks for 2 same/overlapping co-ordinates when game starts? or an easter’s egg to celebrate statistics happens?
  • exploring around this boundary edge-case, Epsilon and Food can be neighbor (side-by-side, or directly up, or directly below). the player will win in one move, won’t they?
  • Board’s size is hard-coded to be 7. I am not making the Board’s size to become adjustable, because of broken visual which is inevitable when board’s size is too large to render to the terminal
  • Although we have “q” key for quit the game, what if user forcefully kill program with Ctrl + C

Final words

I still have ideas to develop the game even more, such as the additional user story i mention earlier, refactoring testing to using pytest and more cases, exploratory testing the game with those edge cases above as starting points.

For now, I would wrap up the MVP of the Epsilon game along with this technical blog. My learning from this project is Git and version control, and develop a Python program.

Original link: https://dev.to/json_todd/codecademy-python-terminal-game-epsilon-the-cat-3i0g

更多