Final Project and Reflection
My Project Choice
Going into the final project, I felt a good amount of trepidation. I was nervous about being able to complete a large-scale coding project and I worried that I wouldn’t be able to complete such a task. Over the course of the semester, I found that I often understood the broad concepts, but hit a wall when trying to write code myself. I would often get errors, be unable to get the programs to do what I wanted, and I’d get frustrated along the way. I sometimes felt like I was lagging behind others classmates who were grasping the materials more effectively and creatively than I was. However, I tried to approach the final project as a learning experience. As we’ve discussed often in class, there is much to be learned by examining our own learning processes and as much as we put pressure on ourselves to avoid “failure,” it is often through these experiences that we learn the most about ourselves and our abilities.
With that in mind, I initially tried to brainstorm an idea for myself that I believed would be attainable. While I debated between the two final options, I ultimately chose to complete a turtle project. I enjoyed the creative element that the turtle programming offers, and I felt that it would help to keep me motivated and engaged throughout the process. The first things that ran through my head were some of the retro-style games of childhood. I initially thought of a block breaker-type game, but I wasn’t sure that I’d be able to complete some of the elements. I then thought of a Minesweeper game. I was confident that I could execute an onclick
function, which was a major component of the game, and I could challenge myself by building it up and making it more complex. I figured I’d be able to implement multiple levels by creating successive boards with more bombs. Going through the requirements, I figured that I’d be able to work through most of them successfully. I didn’t want to get in over my head and begin something that I wouldn’t be able to finish, so I approached it by starting simple and leaving myself room to add difficulty.
My Process for Completion
I began the final project by sketching out the gameboards for the three levels and deciding how I wanted to orient them. I had to plot out where the bombs would be, and then map out the numerical values of the board. For example, if a square touches only one bomb, the value of the square would be one, if it touches two, the square value would be two etc. I repeated this for each level, gradually adding more bombs each time to increase the difficulty.
The first step of the actual coding process was trying to complete the draw_game_board
function. For this, I created a function with for
loops that would draw the board for all the levels. I chose to create a 9x9 board because I figured that multiples of 9 would be easy to deal with (9,18,27,36..)
def draw_game_board():
square_color = "black"
start_x = -130
start_y = -125
box_size = 30
for i in range(0,9):
for j in range(0,9):
draw_box(sam,start_x+j*box_size,start_y+i*box_size,box_size,square_color)
box = "white"
draw_game_board()
Then, I had to effectively created a board full of onclick
functions. I had to figure out the coordinates of all of the squares, which took me longer than I initially thought it would. I know now that there were easier ways of finding the coordinates which would have gotten me there faster, as I explained in previous posts, but I eventually figured out the dimensions of all of the squares on the board. This allowed me to set up all of the the onclick
functions that would allow the turtle to draw a value (1,2,3, or ) when each square was clicked. For example:
#box 1
def box1():
bob.color("light green")
bob.penup()
bob.goto(-115,95)
bob.write("0",None,"center","14pt bold")
def clicky(x, y):
#row 1 (squares 1-9)
if -130 < x < -100 and 85 < y < 115:
box1()
If the user hit a bomb, this triggered a Game Over
screen and a prompt asking them if they wanted to play again. Setting up all of the onclick
functions was a lengthy process because of all of the coordinates involved, but once I was able to get all of the components set up for the first level, it made creating the other levels much easier.
I initially envisioned the main
screen as just the first game board in one of my early drafts, but I realized that the game would need a main
menu upon startup so that the game’s help screen and levels could be displayed. As a result, I made my initial interface screen into game #1. I then created a main
screen with the user options in main.py
. The only way I could think to integrate a dictionary
was to make it the way that the user would choose their level or choose the help option. The dictionary
would launch the game option based on what number they chose. Pressing 4
at any time brings up the help
screen.
One of the next problems that I faced was bringing all of the elements together. I had created the main
interface,level one
,level two
, level 3
and the help
screen in separate trinkets. This actually proved helpful as they provided a backup in the event that I accidentally erased code (which I did a few times…) or tried things that ended up throwing errors. Integrating the levels
into the main interface was tricky, because when I first tried to add in levels to the options on the main screen, the gameboards would just draw over each other. Findings solutions for this took a lot of trial and error. I had to try several different things to get the screen to clear and load each level
independently. Each level is a giant function, which is called with user input on the main
screen, and which then needed to be reset when another option was chosen. To the user input option, I added screen=turtle.Screen()
, screen.reset()
, then aded the level
or help
screen from there. I then reloaded the startup
function to the beginning of the help
screen and level
functions:
def setup(screen):
myscreen=turtle.Screen()
screen.bgcolor("white")
window = turtle.Screen()
window.bgpic('jungle.png')
window.update()
This seemed to work. It cleared the screen, reloaded the correct background, and then displayed the right game or help
option, depending on what number the user chose.
For some reason, the score
function was the area that gave me the most trouble. I had to test some different options to get the flow of control
right. Whenever I felt like I had found a workable solution, it either didn’t work correctly or it only partially worked. In that case, there was usually another problem that was introduced.Finding the right solution felt a little bit like taking two steps forward and one step back. As I mentioned in previous posts, coming up with a way to set up the score
function within the game
function was tricky, because it either didn’t recognize the click
elements or it only worked for the first click but not the others. I finally got it to work by placing the score = 0
piece outside of the game function and the rest within it. This seemed to work without errors. I initially put:
def score(x,y):
global clicks
if (110 < x < 140 and 55 < y < 85) or (-70 < x < -40 and 25 < y < 55) or (-70 < x < -40 and -35 < y < -5) or (20 < x < 50 and -65 < y < -35) or (50 < x < 80 and -95 < y < -65) or (-100 < x < -70 and -125 < y < -95):
clicks -= 0
else:
clicks += 1
sara.penup()
sara.goto(-140, 140)
sara.color("white")
sara.clear()
sara.write("SCORE: " + str(clicks), None, "center", "10pt bold")
myscreen.onclick(score, add=True)
Setting clicks -= 0
worked to keep the program from adding a point when a bomb was hit. However, if the user wanted to replay the game, it continued to add points to the score. Instead, I changed it to clicks = 0
and that seemed to fix the problem, however it also cleared the score
instead of displaying the user’s final score. This wasn’t a big issue, but it would be nice for the user to be able to see how far they made it without the score clearing so quickly. In the interest of time, I didn’t add in a top score
function but this would have been one workaround to this. In the future, I would probably try to add that in, so that a top score
would display as well.
It was also tricky to figure out how to get two onclick
functions to work together. Points could either be added to the score
or the board could be drawn on, but not both. I tried to approach this through the turtle Class
, but I had trouble implementing them correctly. I found that adding add=True
to the second onclick
function to be one solution. So, once I (FINALLY!) had a workable score
function I added that in, which allowed both onclick
functions to work together, adding a point and drawing the values on the board at the same time.
Having the score
function work properly was important because that would be the only way to get the win
screen to really work. When the score
continued to add points upon replaying, as in my first few attempts, the win
screen wouldn’t have been effective because it was triggered by a click count. This wouldn’t have been accurate because the count wouldn’t have been true to the number of squares needed to win. So, having a working solution for the scoring then allowed me to add in the level complete
and win
screens. I made sure to go through and test out all of the levels, to be sure that these were triggered correctly. This was one of the last major steps that I hoped to complete to get the program to work the way that I wanted.
The last thing I needed to complete the project requirements was to import an external data file. I left this one for last because I wasn’t sure how to incorporate this into the game in the same way that we imported CSV files for the data processing assignment. I decided to try to try to corporate it into my help
screen. Initially, I just had a turtle write
the instruction on the screen. But instead I reworked it so that the instructions were imported from a help.txt
file. I found that this was actually a much simpler way of importing text into the game! I wish I had done that sooner because I had to had to play with coordinates a bit, but it was more efficient than having a turtle write out everything.
with open ("help.txt") as file:
for line in file:
bob.write(line.strip(), font=FONT)
bob.goto(-160, bob.ycor() - FONTSIZE)
Areas for Improvement
The program is still a little bit wonky if the user accidentally clicks outside the board because it still counts the click, which is a problem for the scoring. I didn’t realize that was a problem until I did that myself. That’s also something I would need to work on a bit more, to create a score boundary. I would also change the scoring to reflect multiple point values, instead of just one. Another thing is that even though I’m sure I set hideturtle
for all of my game turtles, there is still one that is visable in the game levels. I can’t, for the life of me, figure out where it’s coming from and it doesn’t show up in my individual draft programs. It doesn’t affect the functionality, its just annoying. Overall, though, I’m proud of what I was able to accomplish. From doing multiple trial runs, it is error free and generally works as intended. I’m sure there are other things that I could have added or changed. I know there are probably much simpler, less verbose ways of writing some of my code as well. I’m interested in practicing more and building my knowledge in the future.
General Comments
In general, I was able to keep to my intended schedule throughout the process. I tried to break up the process into smaller milestones. I found that working little by little really helped me to make slow and steady progress without burning myself out. Having the weekly check-ins was helpful for keeping myself accountable and making progress on the things that I wanted to accomplish. I told myself that I would do a reflection for the week of Thanksgiving, just so that I would keep progressing and reflecting on the things that were working and the areas that I needed to continue to work on. This was a really useful exercise in mapping out a trajectory for completion. All in all, this assignment and the class in general really helped me to build a foundation in programming. Starting this class as a total novice, I think I was able to really grow in my abilities. I truly learned a lot about both the material and my own ability to face new challenges.
Final Requirements
- At least one external data file - external .txt file
- Dictionaries - on main.py for level/help option
- Custom modules - main.py, setup.py, help.py, one.py, two.py, and three.py
-
Definite
(for)
loops - gameboard drawing functions -
Custom functions - misc. functions throughout including
score
function -
Have a graphical interface, responding to click events - gameboard is made up of
onclick
functions -
Consistently available help dialog - user can press
4
anytime for help -
Display information about programs state - program shows
level
andscore
- Have at least 3 levels - three levels with increasing # of bombs
-
Extend a custom turtle class - has
Title
andRules
classes -
Have a ‘win’ screen - with a certain score, it triggers a
win
level orwin
game screen - Have an iterative interface - user can play multiple times by pressing 1,2,3 etc. again
- Use one or more custom images - background image
My Final Game
Game Cheat Code
Level 1 Bomb locations: squares 18, 21, 39, 51, 61, 65
Level 2 Bomb locations: squares 6, 21, 25, 29, 40, 46, 53, 61, 66, 78
Level 3 Bomb locations: squares 2, 6, 16, 20, 24, 28, 30, 36, 50, 53, 56, 71, 73, 77, 81