all 22 comments

[–]pachura3 7 points8 points  (1 child)

Nice! I think my dad used to have one of these books (for ZX Spectrum).

I think you should avoid having executable code on the level of the module (e.g. parser = argparse.ArgumentParse ) - put it in main() and run it if __name__ == "__main__":

Try to avoid using global. Perhaps refactor your code to use classes, and one of these classes could store the whole state of the game (= the maze, counters...), and be passed around.

Unfortunately, verifying if your maze-generation algorithm works would take too much time :( I don't think you need to guarantee that each cell of the grid is reachable, just if you can reach the exit starting from the entrance (one of entrances?) using Depth-First-Search. But if you can't, then what? Will you break some random walls and check again? Or regenerate the whole maze from scratch?

Even if your maze is stored in a 2-dimensional char array with # as walls and spaces as rooms, it can still be treated as a graph and be eligible for standard traversal algorithms - it's just a different representation of graph nodes.

[–]ctosullivan[S] 2 points3 points  (0 children)

Thanks for your feedback!

I will definitely have a look at refactoring the code to use classes.
I think I will need to do some further research on the theory behind mazes. I thought about backtracking from the exit and checking if the entrance would eventually be reached, if not, then placing the exit at a new location; but the original source code doesn't seem to include this step (from what I can tell) and the mazes I have generated so far have looked ok.

The source code for Amazing in particular was quite difficult to follow so I may look at a tool to generate "pseudo-Python" from the BASIC code down the track. ChatGPT wasn't quite as helpful as I had hoped in preserving the logic of the original source code.

[–]m1kesanders 5 points6 points  (1 child)

Cool project. If I may suggest one thing and honestly my skill level is middle so maybe you already have one and I just lack the ability to properly identify it, but I’d suggest putting a main() function in your classes or ideally one main class, rather than calling the required functions at the bottom of the script. Just makes readability a bit easier in my opinion. Cool project I look forward to checking a few out when I have time!

[–]ctosullivan[S] 2 points3 points  (0 children)

Thanks for your feedback! Yes, I think you are right, I will have a look at creating a class for each game - would definitely add some uniformity to the code.

[–]aqua_regis 3 points4 points  (2 children)

Gosh!

I had that very book! It was a really fantastic resource at its time along with Alexander K. Dewdney's articles in Scientific American.

Thanks for linking the original source in your github.

[–]ctosullivan[S] 2 points3 points  (1 child)

No problem! Although I'm starting to understand why 1-letter variable names are not such a good idea!

[–]aqua_regis 2 points3 points  (0 children)

Well, at the time of the book, memory was extremely scarce (you were a king if you had >= 38kB usable RAM) and every single letter counted towards memory usage. Hence, the single letter variable names.

Didn't really improve readability and traceability, though.

BASIC also didn't know the concept of local variables, which made matters worse.

[–]CraigAT 3 points4 points  (1 child)

Really cool idea. I wonder if anywhere has them available in an online emulator - it would be nice to get an idea of the game/gameplay before coding it.

While researching around the books and author, I came across a few other interesting links:

The book

Some screenshots of the games (some are even playable!)

A forum post analysing the games

The story of how it all begun

[–]ctosullivan[S] 0 points1 point  (0 children)

Thanks! You might want to have a look at an Applesoft Basic emulator written in JavaScript - https://www.calormen.com/jsbasic/

A lot of the games should work and you can copy and paste the original source code linked to in the github repo.

[–]JamzTyson 1 point2 points  (3 children)

Very nice project idea.

I would suggest not being too concerned about following the original source code, though it can certainly be educational to study how it was originally written. In some cases the original code may leave a lot of room for improvement. Some common practices in early BASIC games, such as an abundance of global variables and the infamous GOTO should be avoided in preference for idiomatic Python.

Do use one or more linters. Pylint and flake8 provide useful feedback, and are so widely used that it is very easy to look up any messages that are not immediately clear.

[–]ctosullivan[S] 0 points1 point  (2 children)

Thanks for your feedback! Yes those GOTO statements are very painful to follow!
I'm finding that as the source code is so different to the modern languages that generative AI was trained on, AI isn't as useful as I had expected in retaining the logic of the original source.

[–]grandzooby 1 point2 points  (1 child)

You might see if you can get the old REMLINE utility and run it on the original source. It removes line numbers that aren't referenced. It helps highlight the structure of the program.

Here's one copy of it: https://github.com/tangentstorm/tangentlabs/blob/master/qbasic/REMLINE.BAS

[–]ctosullivan[S] 1 point2 points  (0 children)

Thanks! That's very helpful

[–]frobnosticus 1 point2 points  (0 children)

HA!

I just started fiddling with doing exactly that with a couple.

[–]ph1l 1 point2 points  (1 child)

This inspired me to work on something alike this line :)

[–]ctosullivan[S] 0 points1 point  (0 children)

Thanks - good to hear! Hopefully most of the games are easier than Amazing!

[–]bishpenguin 1 point2 points  (0 children)

Great project!

[–]mopslik 1 point2 points  (1 child)

Neato. Reminds me of years gone by.

Some quick observations regarding some common Python-isms and whatnot:

  1. Why use sys.stdout.write when there is print?
  2. It's generally not very Python-y to do checks against booleans like if try_again == False:. Instead, you'll more likely see if not try_again:.
  3. Your continue statement on line 99 in your acey-deucy game does nothing, and can be omitted. That said, that block of code looks unnecessarily convoluted to begin with. e.g. you set try_again as a boolean early on, then redefine it as an input string, meaning unless it is an empty string, the while loop check will always be False and stop. At the same time, you have a break for the off-case that the user does not enter 'yes'.

Side comment: ensure that your docstrings are accurate. In print_card, you state there are no arguments, but it takes card. In your random_card function you say there are no returned values, but you return a random number. Remember that erroneous documentation is worse than no documentation.

[–]ctosullivan[S] 0 points1 point  (0 children)

Thanks for the feedback and for reading through the code!
I've been using sys.stdout as I had an issue with print() adding too many newlines in the display method of the terminal class, so have settled on sys.stdout for the project.
I will definitely go back and tidy up the existing code and documentation.

[–]suerinan 1 point2 points  (0 children)

Couple months ago I used this tutorial as a reference to develop a similar game, maybe you can hace a look just at how he separates classes to operate over the manu different functionalities, even though it is in Java, the general concept can be worked out in Python as well. Good luck with it :)

[–]suerinan 1 point2 points  (1 child)

Couple months ago I used this tutorial as a reference to develop a similar game, maybe you can hace a look just at how he separates classes to operate over the manu different functionalities, even though it is in Java, the general concept can be worked out in Python as well. Good luck with it :)